RMI and dynamic class loading

Hi all,

I am facing an issue related to RMI registry and dynamic class loading. I will try to explain this problem clearly..

I have a RMI interface and RMI server which implements the interface, for example (ignore any syntax error for now, just need to get the idea):

interface Server extends Remote {

void doStuff(AbstractEntry ae);

}

AbstractEntry is an abstract class, which just an entry class to store data. It is serializable of course.

In ServerImpl, it will dynamically load a class, let's call it "MyClass", from a jar file, let's call it "a.jar", and its codebase is defined in a property file (you can imagine I am using URLClassLoader to load that class, but actually in my code I am using a custom one). And the major point here is that the class being loaded will be passed in the AbstractEntry (or "ae") and perform operations. So you can imagine that in the "a.jar" there has to have a class, let's call it ConcreteEntry, which extends and implements the AbstractEntry, so that it can be downcasted to something that make sense to MyClass. (You can assume that the client will send the ConcreteEntry over also).

SO! Now the problem comes to the RMI registry (or whatever). My requirement is that when running the server, i cannot set classpath or java.rmi.server.codebase to point to the "a.jar", since the a.jar serves as a runtime library, or like a plugin.

So when I run the registry and server like this (again, not 100% accurate but just to give you an idea):

java -Djava.rmi.server.codebase=standardLib.jar -cp standardLib.jar ServerImpl

When client calls the doStuff function and passes the ConcreteEntry, I will get the error saying the ConcreteEntry class is not found on the client side (some unmarshalling exception). Of course, if I do this, it will work:

java -Djava.rmi.server.codebase=standardLib.jar -cp standardLib.jar;a.jar ServerImpl

So my question is how to meet this requirement?

I have thought of creating a rmi registry in the same process with the class loader i use to load class from codebase, but not seeing how it could work because my classloader can only handle one codebase, and there will be multiple codebases need to be handle, which means multiple registry?!! Also, dunno how to assign the classloader to the rmiregistry afterall... I dunno.. Help!!

Ronald

[2422 byte] By [yingholee] at [2007-9-26 2:09:13]
# 1

There is some confusion on this problem, let me try again to explain:

I am trying to develop a generic server with that Server interface. Client, let's call it "ClientA", is specific client which will use that server interface to execute doStuff(AbstractEntry ae). ClientA has its own imlementation of AbstractEntry, call it "ConcreteEntryA". Client has access to "aClient.jar" which contains that ConcreteEntryA. So far so good right?

On the server side, since server is generic, when the doStuff function is called, it will dynamically load some specific worker class from "aServer.jar". In server jar file, let's call it "server.jar", it only has the AbstractEntry class. In "aServer.jar", however, it contains ConcreteEntryA also. So when the generic server load the worker class and pass in AbstractEntry, the worker class can downcast the entry to ConcreteEntryA and do whatever it wants.

OK, now the problem is when I start the server, I only specify the -Djava.rmi.server.codebase=server.jar. Like this:

java -Djava.rmi.server.codebase=server.jar -cp server.jar Server

It makes sense right? The server.jar will have stub and skeleton, and the AbstractEntry class there, because it is used by the rmi interface.

On the client side, I run the client like this:

java -cp aCLient.jar ClientA

And when I run it and try to execute doStuff(ConcreteEntry ce), I got exception saying unmarshalling exception and cannot found class ConcreteEntryA:

java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:

java.lang.ClassNotFoundException: ConcreteEntryA (no security manager: RMI class loader disabled)

However, if i add aServer.jar to classpath and run the server using this:

java -Djava.rmi.server.codebase=server.jar -cp server.jar;aServer.jar Server

The client will run ok.

So I am just suspecting that the stub or skeleton cannot find the ConcreteEntryA since it is not defined in java.rmi.server.codebase.. I dunno what the problem really is.

Ronald

yingholee at 2007-6-29 8:58:40 > top of Java-index,Core,Core APIs...
# 2
Do you have the remote interface and stubs in aClient.jar?
jetaimeB at 2007-6-29 8:58:40 > top of Java-index,Core,Core APIs...
# 3

Yes, aClient has remote interface and stub.

Actually, I have found a solution for this problem. But it creates another problem.

At the beginning of my server program, I will setSecurityManager to RMISeurityManager, and then I will call this:

Thread.setContextClassLoader(myClassLoader);

So that the whole program will use my custom classloader to load classes. When the skeleton try to serialize ConcreteEntryA, it will be able to find the definition of that class from my external codebase.

This will solve my original problem; however, I am facing another problem, which is for some reason my process will always using 100% of my CPU.. And it has something to do with my custom classloader.

Ronald

yingholee at 2007-6-29 8:58:40 > top of Java-index,Core,Core APIs...
# 4
tryto specify the codebase as file:/<path2yourjar>and see if it helpsregards marco
MmarcoM at 2007-6-29 8:58:40 > top of Java-index,Core,Core APIs...