RMI stub loading problems within Tomcat environment
Hi Java folks,
I encountered something weird in my client-server-application.
First I tried a simple client which has an RMI connection to an RMI server. Client and server reside on different machines. This works fine - the client calls Naming.lookup (<RMI-server-url + service name>) and casts that thing on the common interface used by client and server. Afterwards all methods of the remote objects are available. Fine.
Now I put my (RMI)-client into a servlet. The code for the RMI-connection is similar. The servlet is deployed in Tomcat 3.2.2. Naming.lookup() again returns "some" object. If I use it's toString()-method I can see that the class type is the expected RMI-stub from the server. Now something really odd happens: If I try to cast that stub to my interface I get a ClassCastException!
I have written a main-method to test the servlet outside tomcat. This just calls init() like the servlet enginge would do, and init tries to establish the RMI connection as described above. So if I use that main-method and call init() directly, I can easily cast the stub to my interface. If I use the servlet engine which in turn calls init(), I suddenly cannot cast it to my interface anymore! What the hell happens there?
I can avoid that problem if I put the stub-class-file in a directory in the tomcat servlet directory so that it's inside the classpath. Then the cast will work. This solves my problem, but it's not quite clever. I think the standard way would be that an RMI client (in this case a servlet) just knows about the interface and loads the stub dynamically from the (RMI-)server. The server stub could vary this way and it would still work as the interface stays the same.
Anybody any idea about that?
Regards,
Stefan
[1821 byte] By [
rothi] at [2007-9-26 7:11:29]

The point is I already have that thing running. Only from the DOS-prompt. These are good advice, but I think I already passed these common problems with the codebase, the stub directory etc. (took me some time, though).
So there are just these two slight differences: Start the client manually from the console, all works fine. It gets the stub from the server. Off course I had to use a security manager, with the limitations you described, but these limitations are absolutely acceptable for my part.
Now let tomcat start the client. It also gets the stub. If you've some RMI problems like AccessControlException, ClassNotFoundException you don't get that far like
Object remoteObj = Naming.lookup(name);
If I had any problems with RMI this wouldn't work. I can even print out the class of that returned object. I only get the exception if I cast that object into the common interface:
Object remoteObj = Naming.lookup(name);
System.out.println("Remote-Object: " + remoteObj.toString()); // still works fine!
SimulationRequestBrokerRMIInterface rmiInterface = (SimulationRequestBrokerRMIInterface)remoteObj; // this crashes
for me it looks like there's some serialization error. The client machine gets "some" remote object, and it also seems to be the expected one, the downloaded stub. But it doesn't behave like the expected object. It seems to behave like the expected object only if the client already knows the stub class description, that is it's found in its classpath.
Now perhaps this has something to do with the tomcat environment AND the http-URL I gave as a codebase on the server side? Normally this works fine. Now the tomcat environment, plugged inside an Apache server, perhaps somehow modifies that http-request for stub-downloading? Or filters the incoming bytestream somehow?
The server registry is located by an rmi://... url: (client side)
String name = "rmi://E514626D.erl9.siemens.de:6666/SimulationRequestrokerService";
rmiInterface = (SimulationRequestBrokerRMIInterface)Naming.lookup(name);
It uses as a codebase some http://... to describe the location of the stub (server side): RMI server started with the following script:
set hybrex_home=e:/devel/java/hybrex_web
set java_home=C:/Programme/devel/jdk1.2.2
set host_name=E514626D.erl9.siemens.de
%java_home%\bin\java -classpath ./class;../model/hybrex_web_model.jar;./class/rmi -Djava.rmi.server.codebase="http://%host_name%/server/class/rmi/ http://%host_name%/model/Hybrex_WEB_model.jar" -Djava.rmi.hostname=%host_name% de.siemens.i_s.mp.hybrex_web.server.HybrexWebServer
This is the scenario. Something wrongh about that? Any ideas?
Stefan
rothi at 2007-7-1 16:54:50 >

Stefan
Sounds like you are doing all the right things (though I think there was a missing B in this line:
String name = "rmi://E514626D.erl9.siemens.de:6666/SimulationRequestrokerService";
The short answer is I don't know, but some suggestions:
Please make sure that, when you start RMIRegistry, that classpath is blank and it is being started in some directory well away from your classes, to ensure that the codebase is being correctly annotated to the stubs. Then check that the command line version really does do dynamic class loading as it seems to be by running it in a directory far far away with classpath blank).
If that works fine, maybe it is worth making a little one method test example to check that you can use dynamic class loading from within Tomcat. I'm using RMI from within tomcat successfully, but without using dynamic class loading.
Good luck!
I have the same problem with dynamic downloading of stubfiles in Tomcat
4.0.3 enviroment. Have anyone solved this problem? I have verified that
the RMI stuff works properly with some debug parameters that I found
on the following page:
http://developer.java.sun.com/developer/JDCTechTips/2001/tt0227.html
rmiregistry -J-Dsun.rmi.loader.logLevel=VERBOSE
-Djava.rmi.server.logCalls=TRUE
regards,