views:

519

answers:

3

I wrote an simple project using java rmi and exported to an executable jar file. When I tries to run it, sometimes i got exceptions and sometimes it works. When I specify -Djava.rmi.server.codebase=file:serverClasses/, it seems it didn't create the jar file correctly. Here is the stacktrace:

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: com.ServerBootstrap.IServer
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:413)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:273)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:251)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:377)
    at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
    at java.rmi.Naming.rebind(Naming.java:177)
    at com.v3q6.eece411.A2.ServerBootstrap.ChatRoomServer.main(ChatRoomServer.java:37)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: com.ServerBootstrap.IServer
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:403)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:267)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
Caused by: java.lang.ClassNotFoundException: com.ServerBootstrap.IServer
    at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:336)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:728)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:672)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:609)
    at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:646)
    at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:311)
    at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:255)
    at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1548)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1510)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1749)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1346)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
    ... 12 more

It seems the program doesn't recognize the codebase. In my case, all the files are local. Does anyone know what is the problem? thanks

A: 

That's not a complete stacktrace, and I think you may have left out the part that shows the root cause of your problem.

If I recall correctly, ClassNotFoundException can sometimes be due to an exception thrown during static initialization of the class that is being loaded, or some class that it depends on. If this occurs, it will show up as a nested exception in the first stacktrace for the problem, at the next level of nesting. I recall (maybe incorrectly) that if your application repeats the attempted class load, the initialization exception is not in the resulting stacktrace.

EDIT: The complete stacktrace says that my theory is not correct.

Stephen C
i just put all of them up. Thx
CKeven
A: 

With a relative path specified for java.rmi.server.codebase, make sure that you are in the correct directory (the parent directory of "serverClasses") when starting the client. If that's hard to ensure, an absolute path for the codebase might be more reliable.

Also, remember that when running with the -jar option, the -classpath option is completely ignored. I don't think that's a problem here; the RMIClassLoader should still be able to work using the server's codebase setting. But if you are relying on the client having access to additional classes specified on the classpath, that won't work. You'll need to use the Class-path attribute in the main JAR file's manifest.

erickson
The weird thing is that the program doesn't even recognize the class right in the jar file. Do you know why is that?
CKeven
+1  A: 

Try explicitly specifying the name of the JAR file containing the com.ServerBootstrap.IServer class in your codebase, e.g.

-Djava.rmi.server.codebase=file:serverClasses/myjarfile.jar

The "Dynamic code downloading using JavaTM RMI (Using the java.rmi.server.codebase Property)" doc provides more information on the use of codebase and the options for its specification.

Brandon E Taylor
it works! Is it possible to set it somewhere else so that i dont have to add this every time.
CKeven
@CKeven: you may be able do the same thing using `System.getProperties().setProperty(name, value)` ... provided that you do it early enough.
Stephen C
I dont really know how to do this. Can you please tell me explicitly? thanks
CKeven
All the file the program need is in the jar file. Why shall i bother using the Dynamic code downloading?
CKeven
Dynamic code downloading is the mechanism used to retrieve the classes that are exported by your RMI server. These classes could (and often due in practice when using RMI) reside in JARs that are hosted on a remote server.
Brandon E Taylor
my question is since all the files need is in the jar file, why shall i still specify the codebase?
CKeven
The codebase is what is used when you need to load a class that is exported from the RMI server (your IServer class for instance). Specifying the codebase, then, is necessary to tell your RMI client where it can find the JAR file.
Brandon E Taylor
Is there any way to hide this information and set it within the program to make it more transparent to the user?
CKeven
You can try - as Stephen C. suggested - calling the following within your code: System.setProperty("java.rmi.server.codebase","file:serverClasses/myjarfile.jar");
Brandon E Taylor
it works. Thank you very much
CKeven