views:

141

answers:

2

Hello Stack Overflow...

I have been developing a (somewhat complex) application using RMI to read a file and JSON its contents. I have been coding this app on Netbeans 6.7, therefore I have a folder structure as follows:

Under C:\MyApp:

-build

--- classes

------- MyApp <--- That's a package. My .class files are in there. Also, I ran rmiregistry from here.

-dist

---lib

--------- [some .jar libraries]

-src

...

[Some files]

My application uses a library from the dist\libs folder, and it loads a single file for reading from the current directory, in the [Some files] section.

However, whenever I run the application using: (from the build\classes folder)

java -cp .;..\..\dist\lib\gson-1.4.jar;..\..\..\MyApp -Djava.security.policy=C:\java.policy MyApp.Main

I keep getting ClassNotFoundException errors and a list of errors regarding my RMI interface not being found. The one time it ran, it could not locate the file I need to read. (Got a NullPointerException in my app).

Would you people be able to tell me what I am doing wrong? I believe it's related to the classpath.

Also, if there was a way to run the RMI application from Netbeans itself, it'd be great, but I haven't been able to find any way to do this while searching around.

Oh, rmiregistry is running. And my policy file contains a simple, one-line grant All.

Please help! Thanks!

+1  A: 

I think you sould provide c:\MyApp\build\classes in the classpath and NOT the ..\..\..\MyApp thing that I understand is your project base directory.

At least... with that your java will have access to the classes of your project.

EDIT: example of application without RMIRegistry

If you run your application (the server-side) normally you can publish your RMI-object without rmiregisty tool. It simple creates its own registry reserving and listening in some port you choose.

It's a working example from an application I've made.

The client application will only have to have the interface of the object in its classpath (and all referenced interfaces and classes of course!).

BatchServer is the RMI-object implementing the RMI interface (BatchService) and not extending nothing in particular.

public static void publishAndRun(int port, String name, BatchServer server) throws RemoteException, AlreadyBoundException, NotBoundException
{
    Registry registry = LocateRegistry.createRegistry(port);
    GPRSService stub = (BatchService) UnicastRemoteObject.exportObject(server, 0);
    try
    {
        registry.bind(name, stub);
        try
        {
            server.run();
        }
        finally
        {
            registry.unbind(name);
        }
    }
    finally
    {
        UnicastRemoteObject.unexportObject(server, true);
    }
}

Your client application will have to look for YOUR registry in machine:port and ask for the name object:

    Registry registry = LocateRegistry.getRegistry(server, port);
    BatchService gprs = (BatchService)  registry.lookup(name);
helios
+1  A: 

Thank you Helios. Your answer is informative. I've saved it for future reference if I need it.

Anyway, I managed to solve the problem before an answer was posted. I didn't want to use complex stuff such as codebase and webservers and whatnot.

Firstly, I went to the build\classes folder and ran rmiregistry from there. I know that if it detects the classes in the classpath, it ignores the codebase parameter. That's what I wanted.

Then, I changed that classpath parameter to something simpler. I went to my project root, and then referenced the necessary libraries from there like

-classpath .;dist\lib <the jar files I needed>;build\classes

Finally, for the client, I had the RMI Interface file directly in the main project package. Turns out it should be in the same package as it is on the Server. So I created the necessary package on the client, and placed the RMI Interface there. I was using CodeBase as a start on the client, but kept getting a "$Proxy0 cannot be cast" error which gave me the solution about the package thing.

Now, everything seems to be working. The client can communicate with the server. I tested only on localhost for now, I cannot say if it will work from machines on a network. I believe the ClassNotFound exceptions were due to the RMI registry not being started appropriately (it was not finding the classes.)

Hope my solution is actually appropriate. I don't understand that codebase thing. How it's supposed to dynamically download classes or whatever. I'm still a Java/RMI student/noob.

Inf.S
I don't remember what you need in the client in order to use the server objects without errors, but I think you only need interfaces plus classes directly referenced from them (like parameter objects).
helios