Yes, as the name of the plugin implies, it works with files!
Depending on the client, you COULD write a temp file on the server and stream that, but writing a temp file will use a server path if your client is a web client, a batch processor or a headless client, because these ones really run in a process on the server, saving directly from a smart client would defeat the purpose since you would have to stream the data to the server first before being able to stream them to your client!
Just make sure the place your save your temp file is located inside the default folder of the file plugin and then your will be able to stream to your client.
var dir = plugins.file.showDirectorySelectDialog();
if (dir){
plugins.file.streamFilesFromServer(dir, image);
}
first you ask on the client to show the file chooser to select a directory…
then you get that dir and then you ask to stream files from the server, but the first argument should be the file on the server.
but database streaming, we already have that that is just loading in the record and asking for that data. Then servoy will stream that from the db to the client for you.
streaming blobs from the client to the server is also easy to do, first just create a temp file, write it and then stream it.
What I am trying to do is stream a file from a blob in the database. I didn’t realise that this plugin only deals with files on the server, I misunderstood its purpose.
I originally had the system streaming data directly, but these are 60MB tif files, and as I recall, there was a memory issue (and a database lock up during the delivery of the data) if I simply load it from a blob. Is this no longer a problem in 5.2? (when I did this some years ago, I think it was on Servoy 2.2).
That said, what is the best way to stream data from a blob on the server to a file on the client?
If I stream a file into the default path(/uploads under ROOT path)all works fine but if I try to configure the destination stream path by servoy admin page then something goes wrong…
The main problem is that if I try to put whatever path into the server plugin property than this property completely disappear…to make it visible again I have to go into servoy.properties and remove the line with the plugin configuration.
I’m in windows environment for now(xp and 7),I’ve tried with this property value:
the fact that the property disappears from the admin page is a known bug that has been fixed and will be available in the next Servoy update.
In the meantime, you can set the path in the servoy.properties file, the bug doesn’t affect anything else than the visibility of that property in the admin page, so everything else will work as normal.
When I specify a destination folder that doesn’t exist so the function “streamFilesToServer” will create it!(this is a great thing).
But this not happen into the web client…
So I’ve try to make it by myself and I with the line code: ```
plugins.file.getRemoteFolderContents(‘/’)
My question is: "createFolder" function works on webClient?If yes: How can I create a remote folder without know the remote file struct?(I don't know for example where servoy installation is put,a good way could be to have something that can give me back the remote path or that point directly on remote home-file-plugin-path).
Off course if exist a way to make the function "streamFilesToServer" to create the remote destination folder as do into the smart client would be better.
Thanks in advance
Marco
Marco R.:
When I specify a destination folder that doesn’t exist so the function “streamFilesToServer” will create it!(this is a great thing).
But this not happen into the web client…
It should work in web client too, if not then there is a bug somewhere.
I will have a look.
I have found a problem with the web implementation of the streamFilesToServer() method.
Basically you cannot use “/apath/” + file.getName() because file.getName() returns a full path and not a name (this is coming from the commons file_upload lib), so for example on windows, this will give you a path of ‘/apath/c:/whatever/myfile.jpg’ which is not valid and gives you the exception you had.
I have fixed this so that you can give the path like this:
function onActionFile(event) {
plugins.file.showFileOpenDialog(sendFile);
}
function sendFile(files) {
if (files) {
// note that files here is actually an array, so you can do this:
for (var i = 0; i < files.length; i++) {
var file = files[i];
plugins.file.streamFilesToServer(file,'/sub1/sub2/', uploadFinished);
}
// or simply this:
plugins.file.streamFilesToServer(files,'/sub1/sub2/', uploadFinished);
}
}
function uploadFinished(result, ex) {
if (ex) {
application.output(ex);
} else {
application.output(result.getAbsolutePath());
}
}
In this example, ‘/sub1/sub2/’ will automatically be created on the server in the upload folder declared (or by default in /application_server/server/webapps/ROOT/uploads/), and the files will be put inside this location on the server.
You can also change the name of the file on the server if you prefer, by giving it a full path (with the new file name included), so:
In my case,if I run the solution from the Web, the missing folders aren’t created.
I have tried both on developer and server side.
I have always the same error:
java.io.IOException: Impossible to find the specified path
at java.io.WinNTFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(Unknown Source)
at com.servoy.extensions.plugins.file.WebFileProvider.js_streamFilesToServer(WebFileProvider.java:235)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.mozilla.javascript.MemberBox.invoke(MemberBox.java:179)
at org.mozilla.javascript.NativeJavaMethod.call(NativeJavaMethod.java:353)
at org.mozilla.javascript.Interpreter.interpretLoop(Interpreter.java:3666)
at org.mozilla.javascript.Interpreter.interpret(Interpreter.java:2680)
at org.mozilla.javascript.InterpretedFunction.call(InterpretedFunction.java:166)
at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:387)
at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3127)
at org.mozilla.javascript.InterpretedFunction.call(InterpretedFunction.java:165)
at com.servoy.j2db.scripting.ScriptEngine.executeFunction(ScriptEngine.java:458)
at com.servoy.j2db.plugins.ClientPluginAccessProvider$MethodExecutor.run(ClientPluginAccessProvider.java:511)
at com.servoy.j2db.server.headlessclient.WebClient.invokeAndWait(WebClient.java:482)
at com.servoy.j2db.plugins.ClientPluginAccessProvider.executeMethod(ClientPluginAccessProvider.java:411)
at com.servoy.j2db.scripting.FunctionDefinition.execute(FunctionDefinition.java:195)
at com.servoy.extensions.plugins.file.FileProvider$1.uploadComplete(FileProvider.java:244)
at com.servoy.j2db.server.headlessclient.MainPage$19.uploadComplete(MainPage.java:1250)
at com.servoy.j2db.server.headlessclient.MediaUploadPage$2.onSubmit(MediaUploadPage.java:129)
at org.apache.wicket.markup.html.form.Form.delegateSubmit(Form.java:1545)
at org.apache.wicket.markup.html.form.Form.process(Form.java:938)
at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:900)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.wicket.RequestListenerInterface.invoke(RequestListenerInterface.java:182)
at org.apache.wicket.request.target.component.listener.ListenerInterfaceRequestTarget.processEvents(ListenerInterfaceRequestTarget.java:73)
at org.apache.wicket.request.AbstractRequestCycleProcessor.processEvents(AbstractRequestCycleProcessor.java:92)
at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1250)
at org.apache.wicket.RequestCycle.step(RequestCycle.java:1329)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1428)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:545)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:479)
at com.servoy.j2db.server.servlets.Zl.doGet(Zl.java:15)
at org.apache.wicket.protocol.http.WicketServlet.doPost(WicketServlet.java:160)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:567)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Unknown Source)
If I create the folder manually all works fine.To make me more sure,I have removed the newFileName specification and I have tried with a fixed path:“/donald/goofie/”.So this is my code:
Interesting! When I use the code above this is working for me with virtually the same environment…
“donald” and “goofie” are created and the file placed inside “goofie” as planned.
so 2 questions:
1/ where is your “servoy.FileServerService.defaultFolder” located? Is it the default folder? Another folder? Do you have write access to it, are you sure you don’t have some network policy that prevents you from creating a folder in there?
2/ what is the part of the code which is calling “plugins.file.streamFilesToServer(file[0],‘/donald/goofie/’,globals.myErr);” in your case?
Especially the where does the file[0] comes from? Are you sure that it is not null? Could you do a file[0].getName() and output this to see what’s in it?
so 2 questions:
1/ where is your “servoy.FileServerService.defaultFolder” located? Is it the default folder? Another folder? Do you have write access to it, are you sure you don’t have some network policy that prevents you from creating a folder in there?
2/ what is the part of the code which is calling “plugins.file.streamFilesToServer(file[0],‘/donald/goofie/’,globals.myErr);” in your case?
Especially the where does the file[0] comes from? Are you sure that it is not null? Could you do a file[0].getName() and output this to see what’s in it?
Ok,
1/ in into the default folder,I’m trying it into my personal pc in wich also the application server is installed(so I have server and client on the same machine).
2/ I have attach a solutionSample in wich I reproduce a very similar situation;here ,in my case ,only the smart client work.You can try to use the same path that I have used for the solution test by pressing the corresponding button.
[attachment=0]filePluginTest.servoy[/attachment]
p.s. I have test the webclient with CHROME and IE8, with chrome the code line :“file[0].getName()” return correctly only the file name,with IE8 ,instead, “file[0].getName()” return the full path + file_name.
p.p.s. I have also just updated to java 1.6 u22(I don’t know if there is something different from the java 1.6u21 that impacts on this).
OK, the problem is that the system has no real way to know if you intend to use the second argument as a folder to put the file in, or a complete file path.
I have added some detection to try and guess whether this second argument is a folder - then it won’t try to create a file out of it
You solution works for me now in web client, with either:
p.s. I have test the webclient with CHROME and IE8, with chrome the code line :“file[0].getName()” return correctly only the file name,with IE8 ,instead, “file[0].getName()” return the full path + file_name.
this is know to me yes,
We could and i guess we should make it the same for all platforms, so that getName() only really is the last portion in all the browsers
having the full path there is of no use anyway (its a client path)
I thought we already did something like that.
Unfortunately the problem persist
All works fine exept for the WEB when folder creation is needed. If the destination folder doesn’t exist,this will throw java.io.IOException.If I create the folders manually,all works fine.
To make us more sure we have test the plugin on 3 different pc and environment:
win 7 servoy 1002 java 1.6u20
win xp servoy 1002 java 1.6u20
win xp servoy 1002 java 1.6u22
but we have always the same result both with Chrome and IE8,and both on developer and on the application server.
We have also tried to run both server and client on the same machine and on different machine but without result (I have always used my test solution)
Do I need something other configuration or plugin(exept for standard in servoy)?
Thanks for the updates Patrick. Your latest file now works on the Mac in Developer. For those needing some sample code, below is an example. Basically I had a solution that requires everything that gets printed to save a copy of what gets printed in PDF form as an audit trail of sorts. Below is the sample:
function printPDF(pdfData) {
//pdfData is the binary data for the pdf file. you can get with plugins.pdf_output.endMetaPrintJob()
if(!pdfData)
return
var sFileSep = plugins.it2be_tools.server().fileSeparator
var fileName = sFileSep + "pdf_print" + sFileSep + application.getUUID() + ".pdf"
if(application.getApplicationType() == APPLICATION_TYPES.SMART_CLIENT){
//save the file to the client first
var tFile = plugins.file.createTempFile("print", ".pdf")
plugins.file.writeFile(tFile, pdfData)
//start streaming to the server in a backround process (so we don't have to wait)
plugins.file.streamFilesToServer(tFile, fileName);
//then open it
if(utils.stringMiddle(application.getOSName(),1,7) == "Windows"){
application.executeProgramInBackground('rundll32', 'url.dll,FileProtocolHandler',tFile.getAbsolutePath())
}
else if (utils.stringLeftWords(application.getOSName(), 1) == "Mac"){
application.executeProgram('open', tFile.getAbsolutePath());
}
}
else{
//first save it to the server
var fileDir = plugins.it2be_tools.server().getApplicationServerDir() + sFileSep + "server" + sFileSep + "webapps" + sFileSep + "ROOT" + sFileSep + "uploads"
var sFile = plugins.file.convertToJSFile(fileDir + fileName)
plugins.file.writeFile(sFile, pdfData)
//now stream to client
//in latest versions, this automatically does all the stuff for web client streaming!
plugins.file.writeFile("file.pdf", pdfData)
}
}
FYI: It would be handy if we had the option to SET and GET the servoy.FileServerService.defaultFolder property.
@Johan: I will have a look at being consistent throughout the calls to IUploadData.getName() implementations - this will help fixing the current problem
@Marco: No, you shouldn’t need anything else - I’ll have a look again, and see what could be the case where that breaks for you, most likely it has to do with getName() being inconsistent…
var sFileSep = plugins.it2be_tools.server().fileSeparator
var fileName = sFileSep + "pdf_print" + sFileSep + application.getUUID() + ".pdf"
You can use “/” all the time (think of it as a kind of relative URL - relative to the server default upload folder)
So whatever the platform:
var fileName = "/pdf_print/" + application.getUUID() + ".pdf"
will do just fine!
And I see your point about the getting “servoy.FileServerService.defaultFolder” to be able to use writeFile() in a web client with a server path.
But it will be read only (GET), allowing to change it on the fly would be too much and I don’t see a valid use case… do you really want your users to be able to navigate all over your server’s hard disk?
most likely it has to do with getName() being inconsistent…
Have in your mind that the exception is throwed also with: ```
plugins.file.streamFilesToServer(file[0],serverPath+‘/’,globals.myErr);
so without file[0].getName();
I have tried also your solution sample on the web(I have added the callBack function that is mandatory for the web when anyone use showFileOpenDialog) to make me sure about the correct use of the plugin but the result is always the same.
Marco