5 Replies Latest reply: Mar 10, 2011 1:32 AM by 844347 RSS

    Classpath Issue

    844347
      Hi,

      I am trying to run an RMI example from the book Core Java(TM) 2, Volume II--Advanced Features (7th Edition) and I'm hitting a classpath issue that I cannot figure out. Would anyone know what the solution is here?

      The example is a simple example where the class WarehouseClient.java simply makes a call via RMI to run a method on WarehouseServer.java that returns a value. The code for this example is listed below. A webserver called NanoHTTPD.java is used to dynamically deliver class files.

      The file NanoHTTPD.java is an embeddable HTTP server which I got from here http://elonen.iki.fi/code/nanohttpd/ , so I have not listed the code for that. All the other relevant code to reproduce this is listed at the bottom.

      Here is the directory structure that I have:
      E:\RMI-EXAMPLE-1
      +---core
          +---java
              +---book
                  +---chpt10
                      +---example
                              NanoHTTPD$1.class
                              NanoHTTPD$HTTPSession.class
                              NanoHTTPD$Response.class
                              NanoHTTPD.class
                              NanoHTTPD.java
                              Warehouse.class
                              Warehouse.java
                              WarehouseClient.class
                              WarehouseClient.java
                              WarehouseImpl.class
                              WarehouseImpl.java
                              WarehouseServer.class
                              WarehouseServer.java
      Here are the commands I run:

      * C:\rmiregistry
      * E:\RMI-EXAMPLE-1\java -cp . core.java.book.chpt10.example.NanoHTTPD 8080
      * E:\RMI-EXAMPLE-1\java -cp . -Djava.rmi.server.codebase=http://localhost:8080/ core.java.book.chpt10.example.WarehouseServer
      * E:\RMI-EXAMPLE-1\java -cp .java -cp . core.java.book.chpt10.example.WarehouseClient

      This works and the WarehouseClient gets the value back from the WarehouseServer.


      Now, here is my problem. If I make a small change to the structure of my directories, as follows, it stops working. All I have done is put my core Java package into a directory called classes. So instead of E:\RMI-EXAMPLE-2 being the root of the package, the directory E:\RMI-EXAMPLE-2\classes is the root directory.

      E:\RMI-EXAMPLE-2
      +---classes
          +---core
              +---java
                  +---book
                      +---chpt10
                          +---example
                                  NanoHTTPD$1.class
                                  NanoHTTPD$HTTPSession.class
                                  NanoHTTPD$Response.class
                                  NanoHTTPD.class
                                  NanoHTTPD.java
                                  Warehouse.class
                                  Warehouse.java
                                  WarehouseClient.class
                                  WarehouseClient.java
                                  WarehouseImpl.class
                                  WarehouseImpl.java
                                  WarehouseServer.class
                                  WarehouseServer.java
      Here are the commands I run:

      * C:\rmiregistry
      * E:\RMI-EXAMPLE-2\java -cp classes core.java.book.chpt10.example.NanoHTTPD 8080
      * E:\RMI-EXAMPLE-2\java -cp classes -Djava.rmi.server.codebase=http://localhost:8080/ core.java.book.chpt10.example.WarehouseServer

      But the WarehouseServer throws an exception that it cannot find the Warehouse.class file - I've listed the exception below. Which is strange as I've included the classes directory on the classpath, so why can't it find the class?

      Any ideas why this class cannot be found?


      Thanks,

      Sean.

      Constructing server implementation...
      Binding server implementaiton to registry...
      Exception in thread "main" javax.naming.CommunicationException [Root exception is java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
           java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
           java.lang.ClassNotFoundException: core.java.book.chpt10.example.Warehouse]
           at com.sun.jndi.rmi.registry.RegistryContext.bind(RegistryContext.java:126)
           at com.sun.jndi.toolkit.url.GenericURLContext.bind(GenericURLContext.java:208)
           at javax.naming.InitialContext.bind(InitialContext.java:400)
           at core.java.book.chpt10.example.WarehouseServer.main(WarehouseServer.java:17)
      Caused by: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
           java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
           java.lang.ClassNotFoundException: core.java.book.chpt10.example.Warehouse
           at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:396)
           at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)
           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:886)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
           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.bind(Unknown Source)
           at com.sun.jndi.rmi.registry.RegistryContext.bind(RegistryContext.java:120)
           ... 3 more
      Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
           java.lang.ClassNotFoundException: core.java.book.chpt10.example.Warehouse
           at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
           at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:386)
           at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)
           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:886)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
           at java.lang.Thread.run(Thread.java:662)
      Caused by: java.lang.ClassNotFoundException: core.java.book.chpt10.example.Warehouse
           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:307)
           at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
           at java.lang.Class.forName0(Native Method)
           at java.lang.Class.forName(Class.java:247)
           at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:711)
           at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:655)
           at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:592)
           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:238)
           at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1530)
           at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1492)
           at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
           at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
           at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
           ... 12 more
      package core.java.book.chpt10.example;
      
      import java.rmi.RemoteException;
      
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      
      public class WarehouseServer {
           
           public static void main(String[] args) throws RemoteException, NamingException {
                System.out.println("Constructing server implementation...");
                WarehouseImpl centralWarehouse = new WarehouseImpl();
                
                System.out.println("Binding server implementaiton to registry...");
                Context namingContext = new InitialContext();
                namingContext.bind("rmi:central_warehouse", centralWarehouse);
                
                System.out.println("Waiting for invocations from clients...");
           }
      }
      package core.java.book.chpt10.example;
      import java.rmi.RemoteException;
      import java.rmi.server.UnicastRemoteObject;
      import java.util.HashMap;
      
      
      public class WarehouseImpl extends UnicastRemoteObject implements Warehouse {
      
           private HashMap<String, Double> prices;
      
           protected WarehouseImpl() throws RemoteException {
                prices = new HashMap<String, Double>();
                prices.put("Blackwell Toaster", 24.95);
                prices.put("ZapXpress Microwave Oven", 49.95);
           }
      
           @Override
           public double getPrice(String description) throws RemoteException {
                Double price = prices.get(description);
                return price == null ? 0 : price;
           }
      }  
      package core.java.book.chpt10.example;
      import java.rmi.Remote;
      import java.rmi.RemoteException;
      
      
      public interface Warehouse extends Remote {
      
           double getPrice(String description) throws RemoteException;
      }
      package core.java.book.chpt10.example;
      
      import java.rmi.RemoteException;
      import java.util.Enumeration;
      
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NameClassPair;
      import javax.naming.NamingException;
      
      public class WarehouseClient {
      
           public static void main(String[] args) throws NamingException, RemoteException {
      
                Context namingContext = new InitialContext();
                
                System.out.print("RMI registry bindings: ");
                Enumeration<NameClassPair> e = namingContext.list("rmi://localhost/");
                while(e.hasMoreElements()){
                     System.out.println(e.nextElement().getName());
                }
                
                String url = "rmi://localhost/central_warehouse";
                Warehouse centralWarehouse = (Warehouse) namingContext.lookup(url);
                
                String descr = "Blackwell Toaster";
                double price = centralWarehouse.getPrice(descr);
                System.out.println(descr + ":" + price);
           }
      }
      Edited by: 841344 on Mar 2, 2011 11:47 PM

      Edited by: 841344 on Mar 2, 2011 11:48 PM

      Edited by: 841344 on Mar 2, 2011 11:50 PM
        • 1. Re: Classpath Issue
          jtahlborn
          the problem is probably the rmiregistry. it needs access to the classes as well. you need to specify the classpath for the rmiregistry.
          • 2. Re: Classpath Issue
            844347
            I can't see how the problem is with the rmiregistry needing the classpath.

            Take a look at my initial post, the first example has these set of commands which all run

            * C:\rmiregistry
            * E:\RMI-EXAMPLE-1\java -cp . core.java.book.chpt10.example.NanoHTTPD 8080
            * E:\RMI-EXAMPLE-1\java -cp . -Djava.rmi.server.codebase=http://localhost:8080/ core.java.book.chpt10.example.WarehouseServer
            * E:\RMI-EXAMPLE-1\java -cp .java -cp . core.java.book.chpt10.example.WarehouseClient

            The second example has these set of commands which throw a ClassNotFoundException when I run the server

            * C:\rmiregistry
            * E:\RMI-EXAMPLE-2\java -cp classes core.java.book.chpt10.example.NanoHTTPD 8080
            * E:\RMI-EXAMPLE-2\java -cp classes -Djava.rmi.server.codebase=http://localhost:8080/ core.java.book.chpt10.example.WarehouseServer

            I don't provide a classpath to the rmiregistry in the first example. The command prompt that the command is run from does not have the CLASSPATH environment variable set, so there is no way the rmiregistry has access to the classpath. From that I conclude that the rmiregistry does not need the classpath.

            If the problem was with the rmiregistery, then the first example would not run either.

            So, not quite sure how you can conclude the problem is with the rmiregistry??? What are you basing this on?

            Why should I have to provide the rmiregistry with a classpath in the second example when I don't have to in the first example?
            • 3. Re: Classpath Issue
              EJP
              I can't see how the problem is with the rmiregistry needing the classpath.
              It is. The RMI Registry needs access to the application classes: specifically, the remote interface, the stub if you have one, and any application classes they depend on, and so on recursively until closure. Same as the client.

              Your notation is unclear but I suspect you didn't run RMIRegistry from C:\ either time, despite what your notation suggests. I suggest you ran it from E:\RMI-EXAMPLE-1 in the first case, which has all the .class files available in the directory '.', which is the default classpath; in the second case, you ran it from E:\RMI-EXAMPLE-2, which has the .class files in the directory 'classes', which is not the default classpath, so they weren't found. So in the second case you need to start the registry via rmiregistry -J-Dclasspath=classes.
              • 4. Re: Classpath Issue
                844347
                No. I definitely ran the Rmi Registry from the root folder on the C drive on both occasions.

                To clear up the notation, I ran these commands from DOS prompt on Windows. I thought it was quite clear, but to be 100% correct just replace \ with > i.e.

                The first example has these set of commands which all run with exceptions being thrown:

                * C:>rmiregistry
                * E:\RMI-EXAMPLE-1>java -cp . core.java.book.chpt10.example.NanoHTTPD 8080
                * E:\RMI-EXAMPLE-1>java -cp . -Djava.rmi.server.codebase=http://localhost:8080/ core.java.book.chpt10.example.WarehouseServer
                * E:\RMI-EXAMPLE-1>java -cp .java -cp . core.java.book.chpt10.example.WarehouseClient

                The second example has these set of commands which throw a ClassNotFoundException when I run the WarehouseServer

                * C:>rmiregistry
                * E:\RMI-EXAMPLE-2>java -cp classes core.java.book.chpt10.example.NanoHTTPD 8080
                * E:\RMI-EXAMPLE-2>java -cp classes -Djava.rmi.server.codebase=http://localhost:8080/ core.java.book.chpt10.example.WarehouseServer

                So, how can you conclude the problem is with the RMI Registry classpath. When on both occassions the RMI Registry has no access to the location of the class files from the classpath. My CLASSPATH environment variable is empty also.

                I can't see how in the first set of commands that the RMI Registry is getting the class files from the classpath, how could it?

                Have you run my code examples? Do the first set of commands run for you? Based on your theory the first set of commands should not run (based on the directory setup for the RMI-EXAMPLE-1). But they run for me.
                • 5. Re: Classpath Issue
                  844347
                  I found out what the problem was here. It wasn't with the RMI Registry classpath. The problem was with the webserver I was using to serve the classes - it needs to be started from folder containing the root package for the Java classes so that it can find the Java class when requested for it.

                  I was using these commands, which were throwing an exception:
                  <tt>
                  * C:>rmiregistry
                  * E:\RMI-EXAMPLE-2>java -cp classes core.java.book.chpt10.example.NanoHTTPD 8080
                  * E:\RMI-EXAMPLE-2>java -cp classes -Djava.rmi.server.codebase=http://localhost:8080/ core.java.book.chpt10.example.WarehouseServer
                  </tt>
                  This makes sense to me now as to why it as throwing an exception.

                  * The webserver was being requested for the class <tt>core.java.book.chpt10.example.Warehouse</tt>
                  * The webserver was started from the directory E:\RMI-EXAMPLE-2, so it used this as its root directory to start looking for the class.
                  * This meant that the webserver was looking for the Warehouse.class file in the following location E:\RMI-EXAMPLE-2\core\java\book\chpt10\example , when the actual class file was located in the following directory E:\RMI-EXAMPLE-2\classes\core\java\book\chpt10\example

                  But when I switch to these commands, they run successfully:
                  <tt>
                  * C:>rmiregistry
                  ** E:\RMI-EXAMPLE-2\classes>java -cp . core.java.book.chpt10.example.NanoHTTPD 8080*
                  * E:\RMI-EXAMPLE-2>java -cp classes -Djava.rmi.server.codebase=http://localhost:8080/ core.java.book.chpt10.example.WarehouseServer
                  </tt>

                  Notice that I am now running the webserver from the directory that is the root location of my Java classes\packages.