0

I'm trying to run the example from here

We have a remote interface:

package example.hello;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {
    String sayHello() throws RemoteException;
}

Then we have a server:

package example.hello;

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

public class Server implements Hello {

    public Server() {}

    public String sayHello() {
        return "Hello, world!";
    }

    public static void main(String args[]) {

      System.out.println("Server started");

        try {
            Server obj = new Server();
            Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);

            // Bind the remote object's stub in the registry
            Registry registry = LocateRegistry.getRegistry();
            registry.bind("Hello", stub);

            System.err.println("Server ready");
        } catch (Exception e) {
            System.err.println("Server exception: " + e.toString());
            e.printStackTrace();
        }
    }
}

And then we have a client, although it's not important as it is not what I'm trying to run, at the moment. I followed all the instructions in the link, and I came up with a structure like this:

.
├── example
│   └── hello
│       ├── Client.java
│       ├── Hello.java
│       └── Server.java
└── target
    └── classes
        └── example
            └── hello
                ├── Client.class
                ├── Hello.class
                └── Server.class

Before starting the server I run rmiregistry from the project folder. Then, to run the server I tried, from the project folder too, with:

java -cp ./target/classes -Djava.rmi.server.codebase=file:///Users/myself/Desktop/rmi/target/classes/ example.hello.Server

I also tried with file:/ and with file://, but in all of the cases it gives me:

Server exception: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
    java.lang.ClassNotFoundException: example.hello.Hello
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
    java.lang.ClassNotFoundException: example.hello.Hello
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:421)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:272)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:379)
    at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
    at example.hello.Server.main(Server.java:26)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
    java.lang.ClassNotFoundException: example.hello.Hello
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:411)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:272)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: example.hello.Hello
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.rmi.server.LoaderHandler$Loader.loadClass(LoaderHandler.java:1207)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at sun.rmi.server.LoaderHandler.loadClassForName(LoaderHandler.java:1221)
    at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:731)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:674)
    at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:611)
    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:265)
    at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1566)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
    ... 15 more

From what I got, it cannot find the class, like I'm giving a wrong path. If I start rmiregistry from target/classes, anyway, everything works fine.

My question is, how can I set java.rmi.server.codebase property (included the format) with a relative path so that rmiregistry can be run from a folder different from where the classes are?

acejazz
  • 617
  • 6
  • 18
  • Why? If the classes are present on the local host why not just use the classpath? You’re using a hammer to crack a nut. – user207421 Jan 14 '18 at 01:09
  • I’m simply redoing what is in the Java introduction to RMI, but ideally Client and Server will be in two different hosts. – acejazz Jan 14 '18 at 01:20
  • RMI??? Have you looked at the calendar - it's 2018. – Abhijit Sarkar Jan 14 '18 at 01:54
  • So if they will be in two different hosts, why are you running them in the same host? And why do you think you need to use the codebase feature at all? And what exactly is 'introduction to RMI'? – user207421 Jan 14 '18 at 09:17
  • @AbhijitSarkar Does it sound awful? :) I have to distribute some operations in a synchronous way, with no need to expose API to the external world, so I’m considering some ideas. I’m also considering RESTful API and gRPC. Do you have any suggestions? – acejazz Jan 14 '18 at 09:20
  • @EJP I have to do some distributed work and I’m considering RMI as an option. Since I have no experience with this, I’m trying to start simple with the tutorial that Oracle put in their website (see link on the first line of the post). In that tutorial, they run both client and server in the same machine using the codebase. I thought to start from that simple example and then make it more complex. But I’m not even able to run that simple example, which has no real application. Do you know where I am wrong? Are the guys from Oracle wrong? I’m not asking for the moon. – acejazz Jan 14 '18 at 09:27
  • @AbhijitSarkar: it's 2020 and rmi is still blazingly fast, over the kept open connection I got 1000 calls in 460 ms on the same machine. – weberjn Apr 14 '20 at 13:13

1 Answers1

0

rmiregistry must be started with useCodebaseOnly, too:

rmiregistry -J-Djava.rmi.server.useCodebaseOnly=false

(from Java RMI and ClassNotFoundException)

weberjn
  • 1,535
  • 17
  • 21