简体   繁体   中英

RMI server ClassNotFoundException when client makes call

I am trying to make a simple RMI execution engine to run on my local machine so that other java programs can easily run code on a second processor. (In the future this will be expanded to allow more processors).

The server starts up just fine, and the client appears to locate the registry ok, but when it tries to call the execution engine (and passes it a parameter) it causes a ClassNotFoundException.

I recognize that this is similar to many other questions on stack overflow, but as far as I can tell, all the other ones have to do with the client not being able to download the server's classes rather than the server not being able to download the client's classes.

Here is my code (copied almost exactly from this sample code ):

RMIServer eclipse project

ComputeEngine Interface:

package interfaces;

import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ComputeEngine_IF extends Remote {

    /**
    * @param task The task object specifying the computation to be performed
    * @return
    * @throws RemoteException
    */
    <T extends Serializable> T compute(TaskWithoutInput<T> task) throws RemoteException;
}

TaskWithoutInput interface:

package interfaces;

import java.io.Serializable;

public interface TaskWithoutInput<T> extends Serializable {
    public T compute();
}

ComputeEngine Class:

package server;

import interfaces.ComputeEngine_IF;
import interfaces.TaskWithoutInput;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ComputeEngine implements ComputeEngine_IF{

    public ComputeEngine() {
        super();
    }

    @Override
    public <T extends Serializable> T compute(TaskWithoutInput<T> task) throws RemoteException {
        return task.compute();
    }

    public static void main(String[] args) {
        if(System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }

        try {
            String name = "Compute";
            ComputeEngine_IF engine = new ComputeEngine();
            ComputeEngine_IF stub = (ComputeEngine_IF) UnicastRemoteObject.exportObject(engine, 0);
            Registry registry = LocateRegistry.createRegistry(1099);
            registry.rebind(name, stub);

            System.out.println("Registry bound!");

        }
        catch (Exception e) {
            System.err.println("ComputeEngine exception:");
            e.printStackTrace();
        }
    }
}

RMIClient eclipse project

GetAnswerTask class

package client;

import interfaces.TaskWithoutInput;

public class GetAnswerTask implements TaskWithoutInput<Integer> {

    private static final long serialVersionUID = 1L;

    @Override
    public Integer compute() {
        return Integer.valueOf(42);
    }
}

Client class

package client;

import interfaces.ComputeEngine_IF;
import interfaces.TaskWithoutInput;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RmiClientExample {


    public static void main(String args[]) {
        if(System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }

        try {

            String name = "Compute";
            Registry registry = LocateRegistry.getRegistry("localhost");
            ComputeEngine_IF comp = (ComputeEngine_IF) registry.lookup(name);
            TaskWithoutInput<Integer> getAnswer = new GetAnswerTask();

            Integer answer = comp.compute(getAnswer);
            System.out.println("Answer: " + answer);

        }
        catch (Exception e) {
            System.err.println("RmiClientExample exception:");
            e.printStackTrace();
        }
    }
}

Both projects contain an identical security policy file (in RMIServer it is called server.policy and in RMIClient it is called client.policy)

grant  {
    permission java.security.AllPermission;
};

I will, of course, restrict the permissions more once I get this working.

Building/Running

Since the code is pretty close to something I copied out of an example, my guess is that the code is right, or at least close, but that my mistake is in compiling/running the code. The example wasn't written for eclipse, so I don't have exact instructions.

The first thing I did was use eclipse's jar export wizard to jar the interface package into Interfaces.jar which I just placed in my RMIServer folder.

Then I run ComputeEngine with the following defines:

-Djava.rmi.server.codebase=file:/c:/Users/nate/workspace/RMIServer/Interfaces.jar
-Djava.rmi.server.hostname=localhost
-Djava.security.policy=c:/Users/nate/workspace/RMIServer/src/server.policy

The compute engine seems to run just find and outputs the print statement in the code.

I then run the client with the defines:

-Djava.rmi.server.codebase=file:/c:/Users/nate/workspace/RMIClient/bin/
-Djava.security.policy=c:/Users/nate/workspace/RMIClient/src/client.policy

And I get the following error message:

RmiClientExample exception:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: client.GetAnswerTask
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
    at sun.rmi.server.UnicastRef.invoke(Unknown Source)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
    at com.sun.proxy.$Proxy0.compute(Unknown Source)
    at client.RmiClientExample.main(RmiClientExample.java:24)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: client.GetAnswerTask
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: client.GetAnswerTask
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.rmi.server.LoaderHandler$Loader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClassForName(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
    at java.rmi.server.RMIClassLoader$2.loadClass(Unknown Source)
    at java.rmi.server.RMIClassLoader.loadClass(Unknown Source)
    at sun.rmi.server.MarshalInputStream.resolveClass(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at sun.rmi.server.UnicastRef.unmarshalValue(Unknown Source)
    at sun.rmi.server.UnicastServerRef.unmarshalParametersUnchecked(Unknown Source)
    at sun.rmi.server.UnicastServerRef.unmarshalParameters(Unknown Source)
    ... 13 more

Any thoughts on what I might be doing wrong?

GetAnswerTask implements Serializable, so it will be serialized to the server when you call ComputeEngine_IF.compute() . So GetAnswerTask needs to be available at the server, on its classpath, and it isn't.

For those still struggling with oracle RMI tutorial, whose server doesn't download serializable class from given client's codebase (and stubbornly seeks class in its own codebase) - try to add

-Djava.rmi.server.useCodebaseOnly=false

to server's arguments

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM