New File Stream Plugin

I just finished up with this one from a recent project. It is free to use.
Below is a list of features with a download link…if anyone finds it useful.

Copy a File from the Servoy Application Server to the Client (local network only)

plugins.DDC_FileStream.copyFileFromAppServerToClient(String appServerPath, String clientPath, number bufferSize)

Copy a File from the Client to the Servoy Application Server (local network only)

plugins.DDC_FileStream.copyFileFromClientToAppServer(String appServerPath, String clientPath, number bufferSize)

Copy a File from the Servoy Application Server into a database. (Based on prepared statement). Flushes cache after insert.

plugins.DDC_FileStream.copyFileFromAppServerToDB(String appServerPath, String serverName, String tableName, String preparedStatement)

Download a URL to the client as a File.

plugins.DDC_FileStream.downloadURL(String URL, String clientPath)

Each method has some sample code available from the plugin. It hasn’t been extensively tested, but so far I haven’t encountered any bugs. The only thing to note is that on copyFileFromClientToAppServer & copyFileFromAppServerToClient stream accross Servoy’s RMI port, and they only work accross the LAN, not WAN, or VPN user…I’m really not sure why. So, if you need to have a client on the WAN view a file from the App server, use copyFileFromAppServerToDB to put the file in a BLOB, then in Servoy you can stream it to a temp file and open it.

Download from: http://www.dnacenter.com/servoy/plugin_ … tream.html
or the attachment

ddc_filestream.jar (13.8 KB)

Some examples have been requested on how to use this. Here are a few…

Example #1:
Copy a file from the client to the App Server (file paths are in mac format).

plugins.dialogs.showInfoDialog( "",  "Please choose the File to copy",  "OK")
var clientTemp = plugins.file.showFileOpenDialog()
if(clientTemp)
{
	//a path on the App Server
	var serverLoc = "/Users/admin/Desktop/" + clientTemp.getName();
	
	var success = plugins.DDC_FileStream.copyFileFromClientToAppServer(clientTemp, serverLoc, 1024)
	
	if(success == "true")
	{
		//watever you want
	}
	else
	{
		plugins.dialogs.showInfoDialog( "ERROR",  success + "\n" + serverLoc,  "ok")
	}
}

Example #2:
Copy a file from the Appserver into the database, and open it on the client’s machine in the default program…

First, some module methods:
Method Name: mod_filestr_insertIntoDBFromAppSvrAndViewFile

/******************************************
SB 7/13/06

App Server streams file from local into database, and the 
Client openes the file on their machine (temp file).
If the file already exists, it is just opened.

Parameters:
[0] - fileName (String)
[1] - fileType (ENUM('case_report'))
[2] - serverName (String)
[3] - tableName (String)
[4] - serverFileLocation (String)
[5] - preparedStatement (String)

Returns:
fileName of tempFile
******************************************/

var fileName = arguments[0];
var fileType = arguments[1];
var serverName = arguments[2];
var tableName = arguments[3];
var serverFileLocation = arguments[4];
var preparedStatement = arguments[5];


//Check to see if file is in the DB already
//forms.tbl_file.controller.show()
forms.tbl_file.controller.find()
forms.tbl_file.fle_name = fileName
forms.tbl_file.fle_type = fileType
var count = forms.tbl_file.controller.search()

if(count > 0)
{
	//File exists, so don't insert it again.
	var success = "true"

}
else
{
	//File doesn't exist in the database, so tell the app server to insert it
	var success = plugins.DDC_FileStream.copyFileFromAppServerToDB(serverFileLocation, serverName, tableName, preparedStatement)

}

//create file from BLOB and load to user
if(success == "true")
{
	var a = fileName.lastIndexOf(".")
	var b = fileName.substr(0,a)
	var c = fileName.substring(a)
	var newFile = application.createTempFile(b,c)
	
	forms.tbl_file.controller.find()
	forms.tbl_file.fle_name = fileName
	forms.tbl_file.fle_type = fileType
	forms.tbl_file.controller.search()
	application.writeFile(newFile, forms.tbl_file.fle_file);

	globals.mod_utils_openFileExternal(newFile);
}
else
{
	plugins.dialogs.showInfoDialog( "ERROR",  success + "\n" + serverFileLocation,  "ok")
}

Method Name: mod_utils_openFileExternal

/******************************************
SB 5/22/06

Opens file in default application

Parameters:
[0] - filename (String)

Returns:
NA
******************************************/

var filename = arguments[0];

if(globals.mod_util_isMacOS())
{
	application.executeProgram('open', filename); 
}
else
{
	application.executeProgramInBackground('rundll32', 'url.dll,FileProtocolHandler',filename) 
}

Method Name: mod_util_isMacOS

/******************************************
SB 5/2/06

Returns boolean of OS = Mac.  True if Mac.  False if Windoze

Parameters:
NA

Returns:
boolean
******************************************/

if(utils.stringMiddle(application.getOSName(),1,7) == "Windows")
{
	return false
}
else
{
	return true
}

And Finally, the main method that calls the methods in the modules…

var clientTemp = plugins.it2be_tools.client().tempDir

if(globals.mod_util_isMacOS())
{
	clientTemp += "/" + fle_fileid + ".pdf"
}
else
{
	clientTemp += "\\" + fle_fileid + ".pdf"
}

var serverLoc = "/Volumes/scans-case/" + fle_folder + "/" + fle_fileid + ".pdf";

var preparedStatement = "insert into file values(\"" + fle_fileid + ".pdf\", \"case_report\", \"" +  plugins.it2be_tools.client().MACAddress + "\",?)"

globals.mod_filestr_insertIntoDBFromAppSvrAndViewFile(fle_fileid + ".pdf", "case_report", "misc", "file", serverLoc, preparedStatement);

The prepared statement is based on a file table we have that holds a fileID, useMacAddress, and a BLOB for the file.

How do you stream across the rmi port?
Why don’t you have a client/server plugin where you do the streaming over RMI itself? Because then you shouldn’t have anyproblems by WAN/Internet.

The plugin does stream accross the RMI port, that is how copyFileFromAppServerToDB and copyFileFromClientToAppServer work. However, in my testing, it will not work over the WAN, or a connected VPN user. The AppServer throws the error below…

2006-07-12 08:51 : Error flushing message buffer to client 31354877-119b-11db-bf80-ede2b5b46234, Connection refused to host: 192.168.0.3; nested exception is: java.net.ConnectException: Operation timed out

2006-07-12 08:51 : java.rmi.ConnectException: Connection refused to host: 192.168.0.3; nested exception is: 
	java.net.ConnectException: Operation timed out
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:574)
	at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:185)
	at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:171)
	at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:94)
	at com.servoy.j2db.UserClient_Stub.isAlive(Unknown Source)
	at com.servoy.j2db.dataprocessing.ak.try(Unknown Source)
	at com.servoy.j2db.dataprocessing.j$e.run(Unknown Source)
	at com.servoy.j2db.util.ap.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:613)
Caused by: java.net.ConnectException: Operation timed out
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:430)
	at java.net.Socket.connect(Socket.java:507)
	at java.net.Socket.connect(Socket.java:457)
	at java.net.Socket.(Socket.java:365)
	at java.net.Socket.(Socket.java:178)
	at com.servoy.j2db.util.a.d.createSocket(Unknown Source)
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:569)
	... 8 more

The 192.168.0.3 is the client’s IP on their network, not ours…so that client is not really local to us. I had just figured it was an issue with Servoy because it was looking to host 192.168.0.3, which it will never reach from our network. It appears that when the client’s network uses NAT, it shows the local IP of the client, instead of the WAN address they are connecting from. I don’t know if that is how it is supposed to work…but that is just what I’ve noticed.

Our internal network also runs NAT as 192.168.1.0/255.255.248.0, so technically 192.168.0.3 is within our broadcast range, so could also be an internal IP…maybe that gives it some problems.

I can send the plugin source if you want it.

But the stack you show me is a server log that we generate if a client was disconnected. And we try then once a direct connection.

Normally we don’t call the client ip directly if 2 way socket is enabled (and that should be the case when the client is behind NAT)

So what you see there is something of servoy itself.

Well, that is the only things that show up in the log, and the client does not get disconnected. There is nothing special going on in the plugin…

The server runs the registerRMIService, the client runs the getServerService, and makes calls passing a char Buffer, What I don’t understand is that it works great over the LAN, but not at all over the WAN.

Interested in looking at the code?

you could sent me the code. Or make a case and attach the code to that case in our support system:

http://crm.servoy.com/servoy-webclient/ … oy_support

Thank you. I’ve posted a case in the support system, Case ID: 46915