Sponsored Link •
Sean Neville: Underneath the covers, JRun's RPC method invocations are fundamentally a messaging subsystem. When you perform an invocation, in JRun we actually wrap the invocation in a message object. Onto that message, we can tack transaction IDs, security IDs, thread local info, and more. We can also tack a peer list onto it, so that we can update the client's peer list under the covers.
Bill Venners: What do you mean you wrap the invocation in a message object?
Sean Neville: When you perform an invocation on what appears to be a remote object, no matter what method you invoke, in our invocation subsystem it's routed to a single method that internally generates a message to describe the invocation.
Bill Venners: Like the invoke method of an invocation handler on a dynamic proxy.
Sean Neville: Yes, similar to an invocation handler. We first figure out if we can just invoke the method locally. If we need to make a remote call, we actually wrap the method invocation in something called an invocation context. That name comes from the CORBA intercepting filter pattern, but in our case it's really a message; it is a specific message format that is class-based, not XML-based.
Bill Venners: The invocation context is an object that you're serializing?
Sean Neville: Yes.
Bill Venners: And on the other side, you deserialize it. Now you've got this message object, from which you can retrieve the invocation's parameters and the method that needs to be invoked, plus anything else that has been tacked on.
Sean Neville: That's right. The pattern has been implemented in many ORBs and servers, and in DCOM, and now .NET Remoting. It's probably best described in Pattern-Oriented Software Architecture, Volume 2. When the EJB container gets the invocation message, it passes it through all the filters, before it gets to the instance. So if you have a transaction interceptor, it gets the invocation first. It pulls off the transaction ID, and discovers the transaction attributes of this particular instance. It does whatever it needs to do for the transaction. It then passes it onto the next interceptor, which may put something on or take something off the invocation message. Some folks consider this a Pipes-and-Filters pattern, and in the default cases where the interceptors are hardwired that's a good match. The concept isn't too different from designs that application developers create with servlet filters or message sinks, though in this implementation the container filters are a bit more dynamic and can account for more dependencies than a servlet filter could.
Eventually, the result of the invocation comes back through the intercepting filters and the invocation context message returns to the client subsystem, which will detach the right result or exception. It will also detach the peer list if it needs to update it. So on that message, we can add peer updates to notify clients that objects have joined or dropped out of the cluster.
So as you can tell from all this, Jini is not really in the RPC invocation path. Jini is built into the server, because it is the way we implemented cluster lookup, discovery and events. Using Jini was a great convenience to us because it excels at making those things work in a light and simple way. We used Reggie, Sun's implementation of the Jini lookup service, rather than create our own lookup service.
The fact that we used Jini in JRun has two benefits. First, Jini helped us implement this functionality as quickly and safely as possible. Second, since we now ship a Jini lookup service in a J2EE server, users have a mechanism for doing Jini work without having to start up and configure Reggie, and can now deploy Jini services in the same process as J2EE resources.