Remoting supports the sending of InputStreams. It is important to note that this feature DOES NOT copy the stream data directly from the client to the server, but is a true on demand stream. Although this is obviously slower than reading from a stream on the server that has been copied locally, it does allow for true streaming on the server. It also allows for better memory control by the user (versus the framework trying to copy a 3 Gig file into memory and getting out of memory errors).
Use of this new feature is simple. From the client side, there is a method in org.jboss.remoting.Client with the signature:
public Object invoke(InputStream inputStream, Object param) throws Throwable
So from the client side, would just call invoke as done in the past, and pass the InputStream and the payload as the parameters. An example of the code from the client side would be (this is taken directly from org.jboss.test.remoting.stream.StreamingTestClient):
String param = "foobar"; File testFile = new File(fileURL.getFile()); ... Object ret = remotingClient.invoke(fileInput, param);
From the server side, will need to implement org.jboss.remoting.stream.StreamInvocationHandler instead of org.jboss.remoting.ServerInvocationHandler . StreamInvocationHandler extends ServerInvocationHandler, with the addition of one new method:
public Object handleStream(InputStream stream, Object param)
The stream passed to this method can be called on just as any regular local stream. Under the covers, the InputStream passed is really proxy to the real input stream that exists in the client's VM. Subsequent calls to the passed stream will actually be converted to calls on the real stream on the client via this proxy. If the client makes an invocation on the server passing an InputStream as the parameter and the server handler does not implement StreamInvocationhandler, an exception will be thrown to the client caller.
If want to have more control over the stream server being created to send the stream data back to the caller, instead of letting remoting create it internally, can do this by creating a Connector to act as stream server and pass it when making Client invocation.
public Object invoke(InputStream inputStream, Object param, Connector streamConnector) throws Throwable
Note, the Connector passed must already have been started (else an exception will be thrown). The stream handler will then be added to the connector with the subystem 'stream'. The Connector passed will NOT be stopped when the stream is closed by the server's stream proxy (which happens automatically when remoting creates the stream server internally).
Can also call invoke() method on client and pass the invoker locator would like to use and allow remoting to create the stream server using the specified locator.
public Object invoke(InputStream inputStream, Object param, InvokerLocator streamServerLocator) throws Throwable
In this case, the Connector created internally by remoting will be stopped when the stream is closed by the server's stream proxy.
It is VERY IMPORTANT that the StreamInvocationHandler implementation close the InputStream when it finishes reading, as will close the real stream that lives within the client VM.
By default, the stream server which runs within the client JVM uses the following values for its locator uri:
transport - socket
host - tries to first get local host name and if that fails, the local ip (if that fails, localhost).
port - 5405
Currently, the only way to override these settings is to set the following system properties (either via JVM arguments or via System.setProperty() method):
remoting.stream.transport - sets the transport type (rmi, http, socket, etc.)
remoting.stream.host - host name or ip address to use
remoting.stream.port - the port to listen on
These properties are important because currently the only way for a target server to get the stream data from the stream server (running within the client JVM) is to have the server invoker make the invocation on a new connection back to the client (see issues below).
This is a first pass at the implementation and needs some work in regards to optimizations and configuration. In particular, there is a remoting server that is started to service requests from the stream proxy on the target server for data from the original stream. This raises an issue with the current transports, since the client will have to accept calls for the original stream on a different socket. This may be difficult when control over the client's environment (including firewalls) may not be available. A bi-directional transport, called multiplex, is being introduced as of 1.4.0 release which will allow calls from the server to go over the same socket connection established by the client to the server (JBREM-91). This will make communications back to client much simpler from this standpoint.