Do I need all the classes on the client, server and registry for RMI to work?

I am taking the first steps with RMI and I have a simple question.

I have a .jar file that has an implementation of several methods from the library. I want to call these methods in a .jar file using RMI.

I am trying to create a kind of shell to do this.

So, I am working on something like this:

Interface class This interface has methods that must be implemented by the remote object.

Implementation class . This class has an implementation of the interface methods, each implementation calls the corresponding method in the .jar file. For example, a jar file has a method called getDetails (), and returns a ResponseDetail object. ResponseDetail is the response class that I have in .jar.

Server class : it binds methods to rmiregistry

Client class : he will use the methods implemented in the implementation.

So far so good? :)

Now I have a lib folder where the .jar file is located.

On the server machine, I deployed the interface, implementation, and server classes. I created a stub and I successfully completed rmiregistry, but with these details:

To run rmiregistry, I had to set the classpath on the command line to link to .jar files, otherwise I get java.lang.NoClassDefFoundError. I did this with this .sh file:

THE_CLASSPATH= for i in `ls ./lib/*.jar` do THE_CLASSPATH=${THE_CLASSPATH}:${i} done rmiregistry -J-classpath -J".:${THE_CLASSPATH}" 

To start the server, I had to set the class path to refer to .jar files, otherwise I get java.lang.NoClassDefFoundError. I used something like this:

 THE_CLASSPATH= for i in `ls ./lib/*.jar` do THE_CLASSPATH=${THE_CLASSPATH}:${i} done java -classpath ".:${THE_CLASSPATH}" Server 

Client machine: To run the Client.class file from the client computer, I had to copy the .jar files and refer to them in the class path, because otherwise it does not start, and I get java.lang.NoClassDefFoundError. I had to use this on the client machine:

 THE_CLASSPATH= for i in `ls ./lib/*.jar` do THE_CLASSPATH=${THE_CLASSPATH}:${i} done java -classpath ".:${THE_CLASSPATH}" HelloClient 

This is normal? I mean, do I need to copy .jar files to the client machine to execute methods via RMI?

+7
source share
3 answers

Before JDK v5, you had to create an RMI studio using rmic ( RMI Compiler ). This is done automatically with JDK v5 on. Alternatively, you can run the RMI registry from Java code. To start with a simple RMI application, you can follow these steps:

  • Create an interface:
     import java.rmi.*; public interface SomeInterface extends Remote { public String someMethod1() throws RemoteException; public int someMethod2(float someParameter) throws RemoteException; public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException; } 
  • Implement Interface:
     import java.rmi.*; import java.rmi.server.*; public class SomeImpl extends UnicastRemoteObject implements SomeInterface { public SomeImpl() throws RemoteException { super(); } public String someMethod1() throws RemoteException { return "Hello World!"; } public int someMethod2( float f ) throws RemoteException { return (int)f + 1; } public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException { int i = someStruct.getInt(); float f = someStruct.getFloat(); someStruct.setInt(i + 1); someStruct.setFloat(f + 1.0F); return someStruct; } } 
  • Implement a non-primitive serializable object that must be passed between the client and server:
     import java.io.*; public class SomeStruct implements Serializable { private int i = 0; private float f = 0.0F; public SomeStruct(int i, float f) { this.i = i; this.f = f; } public int getInt() { return i; } public float getFloat() { return f; } public void setInt(int i) { this.i = i; } public void setFloat(float f) { this.f = f; } } 
  • Deploy Server:
     import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry; import java.net.*; import java.io.*; public class SomeServer { public static void main(String args[]) { String portNum = "1234", registryURL; try{ SomeImpl exportedObj = new SomeImpl(); startRegistry( Integer.parseInt(portNum) ); // register the object under the name "some" registryURL = "rmi://localhost:" + portNum + "/some"; Naming.rebind(registryURL, exportedObj); System.out.println("Some Server ready."); } catch (Exception re) { System.out.println("Exception in SomeServer.main: " + re); } } // This method starts a RMI registry on the local host, if it // does not already exist at the specified port number. private static void startRegistry(int rmiPortNum) throws RemoteException{ try { Registry registry = LocateRegistry.getRegistry(rmiPortNum); registry.list( ); // The above call will throw an exception // if the registry does not already exist } catch (RemoteException ex) { // No valid registry at that port. System.out.println("RMI registry is not located at port " + rmiPortNum); Registry registry = LocateRegistry.createRegistry(rmiPortNum); System.out.println("RMI registry created at port " + rmiPortNum); } } } 
  • Customer Deployment:
     import java.io.*; import java.rmi.*; import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry; public class SomeClient { public static void main(String args[]) { try { String hostName; String portNum = "1234"; String registryURL = "rmi://localhost:" + portNum + "/some"; SomeInterface h = (SomeInterface)Naming.lookup(registryURL); // invoke the remote method(s) String message = h.someMethod1(); System.out.println(message); int i = h.someMethod2(12344); System.out.println(i); SomeStruct someStructOut = new SomeStruct(10, 100.0F); SomeStruct someStructIn = new SomeStruct(0, 0.0F); someStructIn = h.someStructTest(someStructOut); System.out.println( someStructIn.getInt() ); System.out.println( someStructIn.getFloat() ); } catch (Exception ex) { ex.printStackTrace(); } } } 

A larger client-server application should be divided into three modules: client , server and common (for classes shared between the server and client code, that is, a remote interface and not a primitive object in this example). Then the client application will be created from client + common modules in the class path and server from server + common modules in the class path.

I used this example many years ago to learn the basics of RMI, and it still works. However, this is far from ideal (the default Java package, improper exception handling, hostname and port parameters are hard-coded and cannot be configured, etc.)

However, this is good for beginners. All files can be placed in one directory and compiled with a simple javac *.java command. Then, the server application can be launched using java SomeServer and the client by running the java SomeClient .

Hope this helps to understand Java RMI, which is actually a lot more complicated than just that.

+6
source

You should not generate stubs (if you follow the tutorial, it's old fashioned). you can run the client, not necessarily using banners locally (using remote class loading), but it is easier to do this with available local banks (I personally made an honest RMI bit and never deployed a system with remote class loading). as a rule, you want to use 2 jars, a β€œclient” bank with only remote interfaces (and any Serializable classes used by these interfaces) and a β€œserver” bank, which includes implementation classes. you would start the server with the server bank and rmiregistry / client with the client banks.

This is a pretty good (modern and simple) getting started guide .

+3
source

In short, other answers have been developed:

  • The client only needs common interfaces (and client classes), not a server implementation.

  • The server needs interfaces and implementation (and the main class of your server).

  • Rmiregistry only needs interfaces.

    (Actually, you can run your own registry inside the server process - then you don't need rmiregistry at all. Look at the createRegistry methods in the java.rmi.registry.LocateRegistry class.)

"Interfaces" here means both remote interfaces and any (serializable) classes that they use as parameters or argument types.

How you distribute these classes in jar files is independent of this.

+1
source

All Articles