OK, so I can use the previously discussed mechanism to allow the user to include arbitrary streams into the request, which are mapped to the remote side by the use of stream handlers.
But one issue that comes up in my mind is the issue of thread safety for the stream objects. Specifically, the local instance might be accessed from any number of I/O handler threads (as things stand currently). This might be OK in some cases (after all, it's little different to how RMI works), but it might not be OK in other cases (after all, it's not like how Remoting 2.x worked at all!).
So here's the solution I propose:
* When the context.invoke() method (which is blocking) is used, then the invoking thread (which would be blocking anyway) will be used to handle requests for local stream objects. This way you can use non-threadsafe objects as stream types without worrying about synchronization or visibility problems. More like Remoting 2.x.
* When the context.send() method (which is non-blocking) is used, then all stream objects included in the request must be threadsafe (since the calling thread will be performing other tasks). More like RMI.
This way, if for some reason you want to use the blocking method but you don't want all your stream callbacks happening in the same thread (and your streams are all threadsafe), you can just do context.send(request).get() instead of context.invoke(request).
On the server side, I think we *could* do some convoluted sticky-thread thing, where streams are always handled by the thread that handled the request, but it's probably just easier to require the server side to always use threadsafe objects. Maybe it would even be a good idea to include wrapper classes for all the stream types that do synchronization.
Best of both worlds? Steaming pile of crap? You decide.
This has been implemented in trunk, and it seems to work OK.