0

I've spent almost five hours trying to resolve this, to no avail. I've created an application that uses RMI. It compiles fine, but I can't it get it to run. All my class files are in C:\Users\Benji\Desktop\ass2\build (short for "assignment"; nothing dirty). All source files are in C:\Users\Benji\Desktop\ass2\src. I've put everything in a single package to make things more comprehensible (and changed the import statements in the source to reflect this).

I have put a batch file in C:\Users\Benji\Desktop\ass2\ . Its contains the execution statement:

java -classpath ./build -Djava.rmi.server.codebase=file:/C:/Users/Benji/Desktop/ass2/build -Djava.security.policy=broker.policy BrokerReception Broker 16890

(The two args "Broker" and "16890" are needed by the program).

The file broker.policy is also in C:\Users\Benji\Desktop\ass2\ . Its contents are:

grant
{
    permission java.security.AllPermission;
};

(and yes, I realise this isn't a good security policy. I'll work on this later).

There are actually three Main classes, one for a client, one for a broker (a mediator for the client) and a server. I am trying to start the Broker. Code for the Broker interface is as follows:

import java.io.FileNotFoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.ArrayList;

public interface Broker extends Remote
{
    public boolean getAvailability(int startDate, int endDate) throws FileNotFoundException, RemoteException;

    public ArrayList<CityInfo> getCities() throws FileNotFoundException, RemoteException;

    public ArrayList<HotelInfo> getCityHotels(int cityNumber) throws FileNotFoundException, RemoteException;

    public int getHotelRoomRate(int hotelNumber) throws FileNotFoundException, RemoteException;

    public boolean makeBooking(String firstName, String lastName, String contact, String creditCardNo) throws FileNotFoundException, RemoteException;
}

And the implementation class:

import java.io.FileNotFoundException;
import java.util.ArrayList;

public class BrokerClientLiaison implements Broker
{
    private BrokerDatabase directory;
    private BrokerHotelsLiaison liaison;

    public BrokerClientLiaison(BrokerDatabase directory, int activeHotelNumber)
    {
        this.liaison = new BrokerHotelsLiaison(activeHotelNumber);
        this.directory = directory;
    }

    public boolean getAvailability(int startDate, int endDate) throws FileNotFoundException
    {
        return liaison.getAvailability(startDate, endDate);
    }

    public ArrayList<CityInfo> getCities() throws FileNotFoundException
    {
        return directory.getCities();
    }

    public ArrayList<HotelInfo> getCityHotels(int cityNumber) throws FileNotFoundException
    {
        return directory.getCityHotels(cityNumber);
    }

    public int getHotelRoomRate(int hotelNumber) throws FileNotFoundException
    {
        return liaison.getHotelRoomRate(hotelNumber);
    }

    public boolean makeBooking(String firstName, String lastName, String contact, String creditCardNo) throws FileNotFoundException
    {
        return liaison.makeBooking(firstName, lastName, contact, creditCardNo);
    }
}

And finally, the main class to start the implementation class:

import java.io.FileNotFoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.sql.SQLException;

public class BrokerReception
{
    public static void main(String[] args)
    {
        System.out.println("Args are:");
        for(String arg : args)
        {
            System.out.println(arg);
        }
        System.out.println();

        try
        {
            BrokerDatabase directory = new BrokerDatabase();
            directory.connect(args[0]);

            int activeHotelNumber = Integer.parseInt(args[1]);
            if(directory.checkActiveHotelExists(activeHotelNumber))
            {
                BrokerClientLiaison liaison = new BrokerClientLiaison(directory, activeHotelNumber);
                Broker liaisonStub = (Broker) UnicastRemoteObject.exportObject(liaison, 0);
                Registry registry = LocateRegistry.getRegistry();
                registry.rebind(Protocol.BROKER_INTERFACE_NAME, liaisonStub);
            }
            else
            {
                throw new FileNotFoundException();
            }
        }
        catch(ArrayIndexOutOfBoundsException aioobe)
        {
            System.err.println("Args required:");
            System.err.println("1. Name of database file");
            System.err.println("2. Number of active hotel");
            System.exit(1);
        }
        catch(ClassNotFoundException cnfe)
        {
            System.err.println("Couldn't load database driver");
            System.exit(2);
        }
        catch(SQLException sqle)
        {
            System.err.println("Couldn't establish connection to database");
            System.err.println("Check that the database has been properly registerd,");
            System.err.println("and that you provided the correct name");
            System.exit(3);
        }
        catch(NumberFormatException nfe)
        {
            System.err.println("Second argument must be an integer");
            System.exit(4);
        }
        catch(FileNotFoundException fnfe)
        {
            System.err.println("The database contains no entries with that hotel number");
            System.exit(5);
        }
        catch(RemoteException re)
        {
            System.err.println("Unable to bind as " + Protocol.BROKER_INTERFACE_NAME);
            re.printStackTrace();
            System.exit(6);
        }
    }
}

"Directory" in the above code is a class that accesses a database.

I don't know what other information I need to give. Can anybody tell me what I'm doing wrong? Incidentally, I went back and did Oracle's RMI tutorial at http://download.oracle.com/javase/1.5.0/docs/guide/rmi/hello/hello-world.html, to see if I could figure out what's wrong. The tutorial makes no mention of codebase or security policy, but provides all the code and precise instructions for compilation and execution. I followed these instructions to the letter, and yet even this didn't work!

Stack trace:

java.rmi.ServerException: RemoteException occurred in server thread; nested exce
ption is:
        java.rmi.UnmarshalException: error unmarshalling arguments; nested excep
tion is:
        java.lang.ClassNotFoundException: Broker
        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:5
35)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTranspor
t.java:790)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport
.java:649)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExec
utor.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(Stream
RemoteCall.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 BrokerReception.main(BrokerReception.java:32)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested ex
ception is:
        java.lang.ClassNotFoundException: Broker
        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:5
35)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTranspor
t.java:790)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport
.java:649)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExec
utor.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: Broker
        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:7
11)
        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:6
28)
        at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294
)
        at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStrea
m.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:1
731)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
        ... 12 more
  • 3
    The stacktrace would be helpful - which class is not found. Try to catch the real classname from `cnfe` in the try..catch handler - maybe, it's not the database driver class... – Andreas Dolk Apr 26 '11 at 09:38
  • ... and also what you are doing when you get it. There are 3 different cases. – user207421 Apr 26 '11 at 11:20
  • Sorry, forgot the stack trace. I've been away a couple of days :/ . The class that isn't found appears to be the broker interface. Also, the strangest thing: I have done a second tutorial, which can be found at http://download.oracle.com/javase/tutorial/rmi/index.html . – Swiftslide Apr 28 '11 at 22:49

1 Answers1

1

if you are running your registry as a second process, it needs access to your remote classes. the easiest way to do this is to add the appropriate classpath argument to the commandline when starting the registry.

if you are trying to use remote class loading, i believe you need to setup an rmi security manager in your application, either on the commandline or in the main method. (personally, distributing the classes usually works for 99% of situations and is 100 times easier to get right).

jtahlborn
  • 52,909
  • 5
  • 76
  • 118