I'm looking at the streaming functionality of remoting and would like to initiate a discussion on its shortcomings and how to address.
First, it looks like the client side creates its own server connector. I don't see a way to customize it other than setting System properties for the transport, host and port. I'm thinking specifically of SSL config - I can have a very specific configuration that my client uses to talk to the server - where my truststore is, my keystore, etc. etc. - as it stands, the streaming server is just created via new Connector() - I don't see a way for me to customize that connector with my own config nor do I see a way to configure the "client" of that streaming server (which is the server that is getting data streamed to it). In other words, I would have SSL set up just the way I want between client->server, but any data I stream down the server via the streaming feature cannot be equally configured with custom SSL settings - a possible security hole.
Second, it would be nice to not have to rely on System properties to define the transport/host/port config for this internal streaming server.
And lastly, is there anyway to have remoting NOT create this streaming server? Since there is already a socket open to the server (my client is talking to the server over the server's normal locator URI), can we get the streamed data to be sent down over that same channel? It seems like we have a pipe there already - we should be able to use it rather than creating a separate server. Creating this separate server created problems such as the need to now configure that server (I don't want to rely on the default transport, host and port) and it will be hard to work with in an environment with firewalls and such.
With those things in mind, are there any other ways to stream data from client to server without relying on this remoting streaming feature? Whether its built in to remoting or something I would have to build - doesn't matter. I just would like to know what ideas there are that would allow me to address the above issues.
Here's what I think I need for my use case.
When I call Client.invoke(InputStream, Object), I want to be able to give it my own Connector. In other words, my client will create and setup its own connector - I just want the Client to wrap my connector in the StreamServer object (the StreamServer will simply add its handler to my connector): e.g. Client.invoke(InputStream, Object, Connector)
There are two issues here:
1) how does the server properly setup ITS client to this connector of mine. Think SSL configuration on the server-side.
2) how do you support concurrent streaming? It is possible that I want to stream data concurrently to either the same or a different server. But StreamServer adds a handler with a hardcoded, constant subsystem of "stream", so its not possible to concurrently serve up multiple streams.
yes, this is absolutely necessary
I think Client.invoke(InputStream, Object, Connector) would be an acceptable solution
and concurrent invocations are also very important
another feature request:
would you be able to develop a solution for simple use that server sends back a stream the client asks for
for example: a ServerInvocatonHandler implementing class tha offers a method, e.g. 'sendStream(InputStream stream, Object param)
and a Client invoke-method like 'obtainStream(Object param)' that returns the stream
So lots of items here. Will try to break them out into groups.
1. How to send streams
Really only two ways to do it. First is to write the actual data to a byte array (or some other data holder) and send the whole thing over the wire. Biggest problem with this is that if large file, will probably get out of memory errors. Second is to remote read on demand of the bytes, so can be writen directly to disk (or whatever) on the server side to avoid running out of memory since don't have to keep all the data in memory. Remoting allows for either, but the Client.invoke(InputStream inputStream, Object param) is for the second option.
2. Client to server and server to client sending of streams
Currently, remoting only allows a client to send a stream (actually a remote proxy to a stream) to the server, which can then read the stream on demand. However, there is no way for the client to read a stream that exists on the server. One of the main reasons for this need to figure out how to define the API for this. I would like this to be a different method since want it to be typed on both sides (meaning both client and server explicitly know they are dealing with a stream now instead of regular object instance being serialized). Also, how to define exactly which file/stream the client wants from the server? The other (probably bigger reason) for not having this is no one has asked for it. If you have a use case, will work on adding it (if you can devise a simple test case illustrating what you are looking for, what would be great).
3. Physical connection for sending streams
As mentioned, the client will create a StreamServer which acts as a remoting server to deliver data from the stream being read to the server instance requesting it (via the stream proxy on the server side). In almost all cases, this is going to require another physical connection to be created from the server instance back to the client instance as the server instance (handler to be more specific) will ask for the bytes from the stream living on the client whenever it wants (so has to be on demand, which requires that connection). This just wouldn't be possible to do using a polling mechanism. So the only way would be possible to do this using the same physical connection would be to use the multiplex transport (which by nature, can use the same physical connection for two-way communication).
4. Concurrent use
I did just make a change for JBREM-519, so that for each StreamServer created, it will use the PortUtil.findFreePort() so that for each time a stream is sent from the client, a new remoting server will be created to receive the stream read requests from the server. This will allows for multiple streams to be read at the same time by the server. I know this is not the greatest option due to having no control over config for ports being used (more in this below).
The current remoting streaming implementation is obviously a very simple one and till now, no one had expressed any interest in using it, so have not devoted a lot of energy to improviing it (obvious by limited config). As you mentioned, can only control basic config info (transport, port, etc.) via setting system properties. I see two immediate ways to make this more configurable (but am open to any other suggestions).
First, can just allow user to send the Connector to use for the StreamServer, as Mazz suggested. This provides complete control over the remoting server used.
However, this is probably a little more work than most people would want to do. So the second option would be to try and do what we do for push callbacks where try to use the same config in use already. So the StreamServer would try to use the same config as already in use by the Client, to include any ssl config if it exists (same for server) and will flip the useClientMode on each side. Will still have the problem of how to configure the port to be used though... not sure how to best do this.
However, this is probably a little more work than most people would want to do.
So, here's a bit of constructive criticism. Don't assume you know how much work a developer wants or needs to do :-) Probably the one and only thing that I really don't like about the remoting API is the lack of full configuration control. Everything else is great! :-)
I disagree that this is probably a little more work than most people would want to do. But, you know your user base better than I, so I could be wrong.
However, I come with a philosophy that APIs should be designed with maximum extensibility and configuration. You probably noticed this with the work I did on the SSL stuff - make everything subclass-able if possible - and make every option customizable/configurable by the developer (again, if at all possible).
There are some things in the remoting API that you just can't do or use because it isn't customizable (the previous SSL stuff and the Transporter stuff are two things that immediately come to mind). The API assumes, and pigeonholes, the developer to use it in a particular way with no way of changing the behavior if I want to. Don't assume you know the way the developer wants to write his code. Its fine to make the "normal" use case easier to write, but while doing that, don't assume you know how the developer wants to do things - don't limit the developer from taking a different approach.
As for this streaming stuff, I have decided that I can't use it due to some of these limitations and am in the middle of implementing my own remote streaming on top of my remoting app. So the good news there for you is you don't have to worry about implementing any of these new feature requests if I'm the only one who asked for it. :)
Ok. Would be interested in seeing what you are doing and if you think would make sense to roll into remoting.