By kcavanaugh on Jun 22, 2006
Sun's app server used rmic -iiop to generate stubs and skeletons for remote EJB interfaces prior to version 8.0. We discovered at that time that at least half the time needed to deploy a remote EJB was spent generating and compiling the stub and skeleton code. Since improving deployment time was an important goal for that release, we decided to eliminate the use of rmic during EJB deployment.
To do this, we needed to generate RMI-IIOP stubs and ties dynamically at runtime. One non-obvious source of complexity in doing this is the RMI-IIOP specification rules (see section 1.3.2 of the Java to IDL mapping specification) for translating between Java method names and IDL operation names. This is complicated for a number of reasons:
- Java supports method overloading, IDL does not.
- Java supports methods contains Unicode characters, IDL does not.
- Java and IDL have different sets of reserved words.
- The rules for valid identifiers in Java and IDL are somewhat different.
We also need to deal with the various rules for marshalling different data types according to the RMI-IIOP specification. To do this, we created the DynamicMethodMarshallerImpl class, which defines how to read and write the arguments and results for a method.
Given the availability of the IDLNameTranslator and DynamicMethodMarshaller, handling Ties is simple (see the ReflectiveTie class). All that we need to do is to write a reflective implementation of the invoke method. The overhead of reflection is insignificant compared to the cost of marshalling and sending the data between JVMs.
Handling Stubs is more complicated. Here the issue is that we need to produce an implementation of the appropriate Remote interface that will delegate all invocations to the ORB, to marshal and transmit the data to the server (and ReflectiveTie implementation). The obvious way to do this is to use a java.lang.reflect.Proxy, but there is a problem with that: all java Proxies must extend the java.lang.reflect.Proxy class. Unfortunately the RMI-IIOP specification requires that the generated stub extend the javax.rmi.CORBA.Stub class, and dynamic proxies cannot support this requirement.
Nevertheless it is possible to directly use the Java proxy to implement a version of RMI-IIOP that complies with every other aspect of the specification but the base class requirement. We have such an implementation available in the GlassFish ORB today. To get full compliance, it is necessary to dynamically generate a class at runtime that extends java.rmi.CORBA.Stub and implements the required remote interfaces. We do this by using BCEL to generate the class. The generated proxy is very simple: the real work is all done in the StubInvocationHandlerImpl class.
No attempt has been made to generate dynamic stubs that are downloadable to other ORBs. After all, if an ORB can generate a stub for any RMI-IIOP invocation, why would we need to download it? Applications that require downloadable stubs are free to use rmi -iiop to generate static stubs and make them available through the RMI classloader. It should also be possible to use our dynamic RMI-IIOP implementation with other ORBs, but this has not been tested.
A more detailed discussion of the dynamic RMI-IIOP implementation is available here in the ORB design docs.
Note that we still support (and will contine to support) the rmic compiler. This is required for J2SE, and also for GlassFish in case the developer needs standard stubs that can be used with another ORB.
Dynamic RMI-IIOP exists in the same form in GlassFish. A few changes
in this area are planned:
- Currently the dynamic RMI-IIOP proxy implementation uses BCEL to generate the proxy code. We will move this to the codegen library (I'll blog about this later), which uses ASM internally for bytecode generation.
- Much of the dynamic RMI-IIOP implementation (particularly the IDLNameTranslator) is also needed for creating a new RMI-IIOP backend for the rmic compiler. We are planning to replace the old backend because it relies on some really obsolete code from the old JDK 1.2 javac compiler. The new backend is planned for the next Java SE release after Java SE 6.
The Dynamic RMI-IIOP implementation is mostly in the com.sun.corba.se.impl.presentation.rmi package in the main source branch in the repository. The BCEL-specific parts are in the com.sun.corba.se.impl.presentation.rmi.bcel package in the optional source branch.