Certainly one of the most important parts of a distributed system is its RPC interface, as well as techniques used in passing that RPC call between different parts of the system.
The component that plays the role of the container entry point, a "call router", to insides of the container is theContainerInvoker. By closely looking at this entry point to the JBoss container, one would understand the semantics of calls made from clients, client object structure, the passing of client calls over the network layer (a.k.a "wire") and unpacking them in a local VM. Similar semantics are employed in returning the result of the call and how it is handled on the client side. Also, great attention has to be dedicated to methods employed in bypassing the network layer if these calls are made from clients local to the container, i.e intra-VM.
Container invoker utilizes RMI exporting* to make itself available to remote clients. By implementingContainerRemote interface, which in turn extends the familiar java.rmi.Remoteinterface, ContainerInvoker acts as an RMI server object and as such is able to accept calls that come from both remote clients (other JVMs) and from other beans "living" in containers of the same EJB application (within the same JVM).
Before going further into the details, let's look closer into ContainerRemote interface. It has two methods, invoke and invokeHome, each of which has two flavors:
public MarshalledObject invoke(MarshalledObject mi) throws Exception;
public Object invoke(Object id, Method m, Object args, Transaction tx, Principal identity, Object credential ) throws Exception;
The first accepts only one parameter (MarshalledObject), while second accepts "regular" java objects. Why is this distinction between the two sets important?
The distinction exists exactly for the reason that it enables the container to accept both remote and local client calls. But it is important to notice that not only does this design approach enable two different call methodologies, it optimizes them at the same time.
Remote calls are unpacked fromMarshalledObject.MarshalledObject contains a byte stream with serialized representation of an object given to its constructor. In our case, this object is RemoteMethodInvocation. The RemoteMethodInvocation instance, created by a remote client proxy, describes all needed attributes of an EJB method call. Some of these attributes, as you may have guessed by now, are the ID of the object, a method to invoke, security credentials, principal of the caller(identity), and a transactional context of the call.
Upon receving MarshalledOjbect from client proxy, ContainerInvoker recreates a copy of the originalRemoteMethodInvocation object, by deserializing it from the contained byte stream in MarshalledObject.RemoteMethoInvocation is then converted to MethodInvocation and handed off to the container.
Local calls coming from clients in the same VM, usually a "bean/bean" method call, are directly handed off to the container. This bypasses the network layer, and serialization/deserialization stage of the call that remote method calls have to go through.
Before forwarding a call to the container,ContainerInvoker also resets the call's thread classloader with the specified container classloader, propagates transaction, and security context.
Another important role played byContainerInvoker is that it provides implementation of EJBObject andEJBHome parts of container. As mentioned before, ContainerInvoker createsEJBObject and EJBHome in the form of dynamic proxies.
For example, an EntityBean finder may result in a set of primary keys whose EJB-objects should be returned to the client. The ContainerInvoker is then responsible for creatingEJBObject instances that can be used by the client, as specified in the EJB 1.1 specification. The client must then be able to remotely access the container and actual bean instances through these EJBObjects.
One may wonder why there is such a big distinction between container invoker and the container.ContainerInvoker also uses the naming tree. Why should the container invoker know anything about the naming tree? You end up having the container invoker taking care of all the important registrations...
Wasn't the container responsible for all this crucial work?
No, this architectural approach was intentional in JBoss. Since different distribution protocols use different naming systems (IIOP would use the CORBA naming system), the only part of the container that knows what naming system to use is the container invoker. Now, if we want to add another/different distribution protocol to JBoss, we can simply implement it in the container invoker; everything else stays untouched. ContainerInvoker is free to choose which distribution protocol to use to access the container. Valid options would be JRMP, IIOP, or SOAP. The default plugin uses the standard RMI protocol JRMP to allow client access to the container.
*Exporting - making object available to accept incoming calls by listening on specified TCP port