Mark Tielemans
Mark Tielemans

Reputation: 1568

RMI UnmarshalException ClassNotFoundException server only

I have followed several tutorials on running an RMI application. However, I can't seem to make it work, as I keep getting stuck on the same exception.

I am, at this point only running a server, so no client communication is involved.

I have a simple RMI program that consists of:

  1. A server class SortServer
  2. An interface ISortFactory<T>
  3. An implementation QuickSortFactory<T>
  4. An RMIUtils class
  5. A policy file allpermissions.policy

Policy file contents

grant { 
    permission java.security.AllPermission;
};

RMIUtils

static {
    // Set policy
    setPolicy();

    // Set Security manager if not present
    if(System.getSecurityManager() == null) {
        System.setSecurityManager(new SecurityManager());
    }

    setHost("127.0.0.1");
}

public static void addCodeBaseFor(Class<?> clazz) {
    System.setProperty("java.rmi.server.codebase", clazz.getProtectionDomain().getCodeSource().getLocation().toString());
}

public static void setPolicy() {
    System.setProperty("java.security.policy", PolicyFileLocator.getLocationOfPolicyFile());
}

public static void setHost(String hostAddress) {
    System.setProperty("java.rmi.server.hostname", hostAddress);
}

public static String getHost() {
    return System.getProperty("java.rmi.server.hostname");
}

SortServer

public static void main(String[] args) throws RemoteException, MalformedURLException, AlreadyBoundException {
    RMIUtils.addCodeBaseFor(ISortFactory.class);

    ISortFactory<String> strQSFactory = new QuickSortFactory<String>();
    // Same error: Naming.bind("rmi://"+RMIUtils.getHost()+"/quicksortfactory", strQSFactory);

    Registry registry = LocateRegistry.getRegistry();
    registry.rebind("quicksortfactory-string", strQSFactory);
}

ISortFactory

public interface ISortFactory<T> extends Remote {
    public ISorter<T> createSorter() throws RemoteException;
}

Implementing QuickSortFactory

public class QuickSortFactory<T> extends UnicastRemoteObject implements ISortFactory<T> {
    private static final long serialVersionUID = -4856366323843718656L;

    public QuickSortFactory() throws RemoteException {
        super();
    }

    @Override
    public ISorter<T> createSorter() throws RemoteException {
        return new QuickSort<T>();
    }
}

ISorter, QuickSorter and referenced objects ISorter extends Remote and its methods throw RemoteExceptions. QuickSort extends SortLogic and implements ISorter. Its methods throw RemoteExceptions. SortLogic extends UnicastRemoteObject. Its methods throw RemoteExceptions.

Since I use JDK 1.5+, I shouldn't need to worry about stubs. The rmiregistry is running fine, or I would have different errors.

Literal console output

2013-11-20 00:57:00 DEBUG RMIUtils:33 - Policy file path changed to 'C:\Users\Mark\AppData\Local\Temp\rmi-sorter5248481413010560777.policy'
2013-11-20 00:57:00 DEBUG RMIUtils:38 - RMI hostname set to 127.0.0.1
2013-11-20 00:57:00 DEBUG RMIUtils:27 - Codebase path added: file:/F:/Development/Git/Personal/parallel-sorter/bin/
Exception in thread "main" java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: nl.marktielemans.rmisorter.server.factory.ISortFactory
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:400)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:248)
    at sun.rmi.transport.Transport$1.run(Transport.java:159)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:662)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:359)
    at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
    at nl.marktielemans.rmisorter.server.SortServer.main(SortServer.java:42)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: nl.marktielemans.rmisorter.server.factory.ISortFactory
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:390)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:248)
    at sun.rmi.transport.Transport$1.run(Transport.java:159)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.ClassNotFoundException: nl.marktielemans.rmisorter.server.factory.ISortFactory
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:249)
    at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:709)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:653)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:590)
    at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:628)
    at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294)
    at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:242)
    at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1535)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1491)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1748)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1327)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:349)
    ... 12 more

Without codebase parameter

I've tried without codebase parameter, but am not sure how to include the classes in the RMI classpath as I read I should.

I've tried starting the registry from the code in SortServer using RegistryLocator.getRegistry() as above, as well as starting it from a command line opened in my bin directory. Still, I would get the same error.

Upvotes: 3

Views: 9369

Answers (1)

user207421
user207421

Reputation: 310850

java.lang.ClassNotFoundException: nl.marktielemans.rmisorter.server.factory.ISortFactory
...
at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)

The Registry doesn't have that class available in its CLASSPATH.

If you're using the java.rmi.server.codebase property you need to set it before exporting any remote objects, and the codebase needs to be something the Registry and the clients can use.

public static void addCodeBaseFor(Class<?> clazz) {
    System.setProperty("java.rmi.server.codebase", clazz.getProtectionDomain().getCodeSource().getLocation().toString());
}

This isn't going to work. The location on the server of the containing JAR file can't be seen from the client. Generally it is an http: or ftp: URL.

Upvotes: 2

Related Questions