Link to home
Start Free TrialLog in
Avatar of vsaritha_9
vsaritha_9

asked on

RMI Stub copying in the client side

Hello,
I am writing a cimple application in RMI.
How can I get the client stubs in the client system. do we need to copy the stubs on the client machine explictly.

If i am having the client and server in the same machine then i am explictly copying the stubs into the client directly. If i have client and server in different machines, then in this case too do I need to copy the stubs in the client. Does it cannot be made automatically.
Please if possible can u give the procedure.
Hope to see replies soon
Thanking you all
Saritha
Avatar of girionis
girionis
Flag of Greece image

> If i have client and server in different machines, then in this case too do I need to copy the stubs in the client.

  No you don't. The RMI client should download the stub files needed automatically.
 ... you will also need to install a security manager (required by any VM that needs to download code) in order for the RMI client to freely download stubs and other classes needed.
You need the stubs on your classpath to compile your client.
You execute your client you also need the stubs on the client classpath. It make no diffence wether the client is executed local (client/server on same machine) or not.

Avatar of msterjev
msterjev

The procedure is follows (for interface IHello):

The server side

1. Create interface IHello extending Remote
2. Create the interface implementation HelloImpl.Don't forget setting RMISecurityManager.
3. Compile the stubs with rmic.
4. You need the web server. Put the IHello and HelloImpl_Stub classes into the web server public accesible path. For example: http://somewhere/classes/.
5. Create policy file for all permissions, for example:
grant
{
   permission java.security.AllPermision;
};
6. Start rmiregistry with shell unseted classpath.
7. The key step is properly starting the application. You should set java.security.policy property and java.rmi.server.codebase properties.
For example:
java -Djava.security.policy=policy.all -Djava.rmi.server.codebase=http://somewhere/classes/ HelloImpl
8. You can watch your web server activity and you can see there is access to the IHello and HelloImpl_Stub during the application startup.

The client side:

The client needs only interface IHello.

1. Don't forget to set RMISecurityManager.

Anything else is postponed into the client startup. Because it is going to download the Stub class it need the policy file installed. You can use policy.all file. Start the client with:

java -Djava.security.policy=policy.all HelloClient

How the rmi works. The RMI works with the special object serialization. The steps are as follows:

1. After Naming.lookup(), the client receives the serialized stub (from the exported UnicastRemoteObject on the server's side). The client looks for a specified class in order to perform deserialization of the object, but it can't find such a class into it's classpath.RMI takes a use of additional parameters with object serialization, i.e. the URL where the client can't find the class definition. So, the client downloads the class definition from the web server's. When the class is there, the client can deserialize the serialized stub and instatiate it. After that, the client's and server's can communicate. The same princip is used with RMI method call arguments.Each user's created serialized argument, also delivers information where the class definition can be finded.
Avatar of vsaritha_9

ASKER

hi msterjev,
How should i set the RMISecurity manager. when i a m saying
System.setSecurityManager(new RMISecurityManager());
I am getting
java.security.AccessControlException: access denied (java.net.SocketPermission
27.0.0.1:1000 connect,resolve)

how should i sort this problem. U have asked to write a policy file. I am not using as webserver right now. Do i need to compulsorily use web browser to download stubs.

Please let me know this soon.. I m very thankful to you.
Regards
Saritha
The policy file you should use for experimenting is the simplest one and it is as follows:

grant {
    permission java.security.AllPermission "", "";
};

I've written before how the command line should look like:

1. For the server:

java -Djava.security.policy=policy.all -Djava.rmi.server.codebase=http://somewhere/classes/ HelloImpl

2. For the client:

java -Djava.security.policy=policy.all HelloClient

So the policy file grants the all permissions. In the deployment scenario you should write more restricted policy file (See Sun's online Java Tutorial- section for RMI).

About, using a Web Server:
 If you don't have a web server, you can obtain a simple SUN's implementation ClassFileServer. But I think the Web Server is not a problem. What operating system you are working on? If it is a Windows environment the Personal Web Server suffices.
Yes, you should use Web Server if the client and the server are on different machines in order for Stub downloading. If you are testing locally, you can use file URL for java.rmi.server.codebase.

java.rmi.server.codebase=file:/C:/somewhere_not_in_classpath/

Don't forget the slash at the end!

My previous comment was intention to explain what happens behind the RMI scene. If you want the step by step example (there is also a reference for downloading and using SUN's ClassFileServer) you can read this article:

http://www.eli.sdsu.edu/courses/spring99/cs696/notes/ddc/ddc.html

Regards
Hi,
I m first writing an example for testing.Later i will use web broswer. this is the exception i m getting.
java.security.AccessControlException: access denied (java.io.FilePermission \\D
Users\Saritha\java\examples\RMI\Server\serv read)
        at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unkno
n Source)
        at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
        at sun.rmi.server.UnicastRef.invoke(Unknown Source)
        at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
        at java.rmi.Naming.rebind(Unknown Source)
        at Server.serv.RMIExampleImpl.main(RMIExampleImpl.java:38)

if i include  
permission java.io.FilePermission "<<ALL FILES>>", "read, write, delete, execute"; in policy file then i am getting the AccessControlException.

Here is the commands which i have used:
Server:
java -Djava.rmi.server.codebase=file://D:/Users/Saritha/java/examples/RMI/Server/serv/

-Djava.security.policy=D:/Users/Saritha/java/examples/RMI/Server/serv/policy Server.serv.RMIExampleImpl

Client:
java -Djava.security.manager -Djava.security.policy=d:/users/saritha/java/examples/rmi/Client/policy RMIExampleClient

in implementation class i have downloaded the RMISecurity manager using new RMISecurityManagaer().

What went wrong

Thanks for the Help.
I am not able to sort out the problem which i m trying since morning
Saritha
file:///D:/Users/Saritha/java/examples/RMI/Server/serv/

I've added one aditional slash with file:///

I'm waiting for comment!
And try with the policy.all file at the begging. When you develop something you should provide it works and pass the tests. After that you should provide deployment policy. This the way you can localize the problems!
Hi,
Thank you. Now i am not getting that exception at server side. But i am getting same exception at client side. Thats is when i run the clinet. I have used the policy.all file as the policy file.
I m now sorting the problem.Thank you very much. Is the command line that is used for the clinet is correct.
Thank you very much
Saritha
Hi,
I ma ble to solve that problem. Now i m getting ClassNotFoundException. stub class not found.I m trying to sort that problem
What is the exception?
What is the exception?
 Check your classpath and make sure the stub classes are there.
The exception is
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
        java.lang.ClassNotFoundException: Server.serv.RMIExampleImpl_Stub
java.lang.ClassNotFoundException: Server.serv.RMIExampleImpl_Stub
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Unknown Source)
        at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
        at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
        at sun.rmi.server.MarshalInputStream.resolveClass(Unknown Source)
        at java.io.ObjectInputStream.inputClassDescriptor(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at java.io.ObjectInputStream.inputObject(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
        at java.rmi.Naming.lookup(Unknown Source)

I have my Implementation class in Server.serv package and interface in Server.inter package.
The above is the exception i am getting. This is the command i used.

java -Djava.security.manager -Djava.security.policy=d:/users/saritha/java/examples/rmi/policy RMIExampleClient

 Try this:

java -classpath <path to your server classes> -Djava.security.manager -Djava.security.policy=d:/users/saritha/java/examples/rmi/policy RMIExampleClient
what if the servers are in the different machine. How should i refer to the server classpaths. I m not using any webserver for this.
1. You should start the rmiregistry from the console with unset classpath. So start new console and write:

SET classpath=

The type:

start rmiregistry


You should also put the Stub and Interface classes where classpath is not point to, so the file codebase is the only way to load the classes (they can't be finded in the local classpath).

Also check the correct file codebase path!!!
 Your client will download then automatically from the URL defined, either as parameter or inside your client code.
The problem is not in the client,I'm sure. The problem is in the server!!!! The when you have started the server, the classes UnicastRemoteObject is exported using local classpath. You should specify the -Djava.rmi.server.codebase=file:///somehwere_not_in_the classpath/

This would solve the problem :-)
 Ok lets get things step by step...

  Can you make sure the RMI registry and the server are running?
I m doing same
This is the batch file i have used to compile and run the client program.

set classpath=.;

javac -d Client Client/RMIExampleClient.java

cd Client

java -Djava.security.manager -Djava.security.policy=d:/users/saritha/java/examples/rmi/policy -Djava.rmi.server.codebase=file:///D:/Users/Saritha/java/examples/RMI/Server/serv/ RMIExampleClient

Still I am getting same exception
I m doing same
This is the batch file i have used to compile and run the client program.

set classpath=.;

javac -d Client Client/RMIExampleClient.java

cd Client

java -Djava.security.manager -Djava.security.policy=d:/users/saritha/java/examples/rmi/policy -Djava.rmi.server.codebase=file:///D:/Users/Saritha/java/examples/RMI/Server/serv/ RMIExampleClient

Still I am getting same exception
Is problem with packaging the implementation class.
 .. can you also post the commands you are using to run your server?
These are the commands i have used.
cls
set classpath=.;
javac -d . Server/inter/RMIExampleInter.java

javac -d . Server/serv/RMIExampleImpl.java

rmic Server.serv.RMIExampleImpl

start rmiregistry

start java -Djava.rmi.server.codebase=file:///D:/Users/Saritha/java/examples/RMI/Server/serv/ -Djava.security.policy=D:/Users/Saritha/java/examples/RMI/policy Server.serv.RMIExampleImpl

You are not listening what I'm telling you! So I give up!
 Ok I assume the server is running fine now.

  Do for your client:

 java –cp <path to client class> -Djava.security.policy=<path to yur policy> <ClientClass>
hey msterjev,
I m listening you. I have given my sever commands too and i am very much sure that the path used in the codebase is not in my classpath..i have given you all the commands i am using..Please help me.
By the way, If you don't using custom serialized objects, you  should not specify java.rmi.server.codebase when you start the client!
Did you start rmiregistry properly?
Start new console, go to C:\ and type:

Set classpath=

Then start rmiregistry.

yes i jave started
 Can you try to run the client as I suggestd above and let us know what happens?
I m really fed up..
Thank a lot for being so pacient and answering my questions. Now when i have started rmi registry as u have said from c: drive and after running the server from the d drive i am getting the following exception
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: Server.serv.RMIExampleImpl_Stub
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:

        java.lang.ClassNotFoundException: Server.serv.RMIExampleImpl_Stub
java.lang.ClassNotFoundException: Server.serv.RMIExampleImpl_Stub
        at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknow
n Source)
        at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
        at sun.rmi.server.UnicastRef.invoke(Unknown Source)
        at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
        at java.rmi.Naming.rebind(Unknown Source)
        at Server.serv.RMIExampleImpl.main(RMIExampleImpl.java:38)

I have run the same command which i run through command prompt. there it worked fine but now it is giving exception. I think i have messedup something. If u get any clue what wrong i have done then please let me know.till i will sort out.

I Thank you very very much for helping me
Here is a step by step example:

1. I have the following folder:

E:\RMIHelloWorldServer

with the following files:
HelloWorld.java
HelloWorldImpl.java
policy.all
StartServer.bat

The context of each file is:

HelloWorld.java

import java.rmi.*;

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

HelloWorldImpl.java

import java.rmi.*;
import java.rmi.server.*;

public class HelloWorldImpl extends UnicastRemoteObject implements HelloWorld
{
     
     public HelloWorldImpl() throws RemoteException
     {
          super();
     }
     
     public String sayHello(String name)
     {
          return "Hello "+name;
     }
     
     public static void main(String[] args)
     {
          if(System.getSecurityManager()==null)
               System.setSecurityManager(new RMISecurityManager());
          try
          {
               HelloWorldImpl hw=new HelloWorldImpl();
               System.out.println("HelloWorldImpl exported!");
               Naming.rebind("rmi://localhost/Hello",hw);
               System.out.println("HelloWorld bound to registry...");
          }
          catch(Exception e)
          {
               e.printStackTrace();
          }
     }
}

policy.all

grant
{
     permission java.security.AllPermission "","";
};

StartServer.bat

java -Djava.security.policy=policy.all -Djava.rmi.server.codebase=file:///E:/RMIHelloWorldServer/ HelloWorldImpl



type:

javac *.java

type

rmic HelloWorldImpl

Start new console!

type

set classpath=

type

rmiregistry

In the E:\RMIHelloWorldServer console type:

StartServer

The server would be starte and bound to registry!

I've also have the E:\RMIHelloWorldClient folder with the following files there:

HelloWorld.java
HelloWorldClient.java
policy.all
StartClient.bat

HelloWorldClient.java

import java.rmi.*;

public class HelloWorldClient
{
     public static void main(String[] args)
     {
          HelloWorld hw;
          if(System.getSecurityManager()==null)
               System.setSecurityManager(new RMISecurityManager());
          try
          {
               hw=(HelloWorld)Naming.lookup("rmi://localhost/Hello");
               System.out.println(hw.sayHello("Saritha"));
          }
          catch(Exception e)
          {
               e.printStackTrace();
          }
     }
}


StartClient.bat

java -Djava.security.policy=policy.all HelloWorldClient

Into the new console for path E:\RMIHelloWorldClient type

StartClient




Do you think about awarding this lengty discussion :-))?
Ok let me try it on my computer and I will get back to you soon.
I will definitly award with lots of points..
I have few doubts in this too..please don't get irritated. Is ur client program is in the same mechine as server. and client need the interfce of the server. In ur client program u have't imported that interface. this is the code which i have used. Please work with it and let me know.

Interface:
package Server.inter;

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


public interface RMIExampleInter extends Remote{
     public void setString(String str) throws RemoteException;
     public String getString() throws RemoteException;
}

Server:
package Server.serv;

import Server.inter.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.rmi.registry.*;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;

public class RMIExampleImpl extends UnicastRemoteObject implements RMIExampleInter{
     
     private String str = null;
     
     public RMIExampleImpl() throws RemoteException{
          super();
     }

     public void setString(String str) throws RemoteException{
          this.str = str;
     }
     
     public String getString() throws RemoteException{
          return str;
     }
     public static void main(String args[]){
          try{
               
               RMIExampleImpl obj = new RMIExampleImpl();
               
               if (System.getSecurityManager() == null) {
                    System.setSecurityManager(new RMISecurityManager());
               }

               System.out.println("Starting Server..............");
               System.out.println("Server Started");

               // Bind this object instance to the name "RMIExample"
               Naming.rebind("rmi://localhost:1099/RMIExample", obj);

               System.out.println("RMIExample bound in registry");

          }catch(Exception e){
               e.printStackTrace();
          }
     }
}

Client:
import Server.inter.*;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;

public class RMIExampleClient
{
     
     public static void main(String[] args)
     {
          RMIExampleInter rmiExample=null;

          try{

               if (System.getSecurityManager() == null) {
                    System.setSecurityManager(new RMISecurityManager());
               }

               System.out.println("Attempting to connect to RMIExample....");
               Remote remoteObj = Naming.lookup("rmi://localhost:1099/RMIExample");

               if(remoteObj instanceof RMIExampleInter){
                    rmiExample = (RMIExampleInter) remoteObj;

                    System.out.println("Invoking Remote method");
                    rmiExample.setString("Saritha");                    
                    System.out.println("Getting the String:"+rmiExample.getString());

               }else{
                    throw new Exception("Bad Remote Object");
               }
          }catch(Exception e){
               e.printStackTrace();
          }
     }
}

This is the code which i have been using and i think this document already contains the commands i used to execute and run the client and server code.

I thank you very very much.
Regards
Saritja
I will definitly award with lots of points..
I have few doubts in this too..please don't get irritated. Is ur client program is in the same mechine as server. and client need the interfce of the server. In ur client program u have't imported that interface. this is the code which i have used. Please work with it and let me know.

Interface:
package Server.inter;

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


public interface RMIExampleInter extends Remote{
     public void setString(String str) throws RemoteException;
     public String getString() throws RemoteException;
}

Server:
package Server.serv;

import Server.inter.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.rmi.registry.*;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;

public class RMIExampleImpl extends UnicastRemoteObject implements RMIExampleInter{
     
     private String str = null;
     
     public RMIExampleImpl() throws RemoteException{
          super();
     }

     public void setString(String str) throws RemoteException{
          this.str = str;
     }
     
     public String getString() throws RemoteException{
          return str;
     }
     public static void main(String args[]){
          try{
               
               RMIExampleImpl obj = new RMIExampleImpl();
               
               if (System.getSecurityManager() == null) {
                    System.setSecurityManager(new RMISecurityManager());
               }

               System.out.println("Starting Server..............");
               System.out.println("Server Started");

               // Bind this object instance to the name "RMIExample"
               Naming.rebind("rmi://localhost:1099/RMIExample", obj);

               System.out.println("RMIExample bound in registry");

          }catch(Exception e){
               e.printStackTrace();
          }
     }
}

Client:
import Server.inter.*;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;

public class RMIExampleClient
{
     
     public static void main(String[] args)
     {
          RMIExampleInter rmiExample=null;

          try{

               if (System.getSecurityManager() == null) {
                    System.setSecurityManager(new RMISecurityManager());
               }

               System.out.println("Attempting to connect to RMIExample....");
               Remote remoteObj = Naming.lookup("rmi://localhost:1099/RMIExample");

               if(remoteObj instanceof RMIExampleInter){
                    rmiExample = (RMIExampleInter) remoteObj;

                    System.out.println("Invoking Remote method");
                    rmiExample.setString("Saritha");                    
                    System.out.println("Getting the String:"+rmiExample.getString());

               }else{
                    throw new Exception("Bad Remote Object");
               }
          }catch(Exception e){
               e.printStackTrace();
          }
     }
}

This is the code which i have been using and i think this document already contains the commands i used to execute and run the client and server code.

I thank you very very much.
Regards
Saritha
 Don't worry about the points. I will try it and let you know...
The problem is with your's codebase. It must be:
file:///D:/Users/Saritha/java/examples/RMI/

instead of

file:///D:/Users/Saritha/java/examples/RMI/Server/serv/

because the codebase must be into the root where class packages begin!

Enjoy!
 Put all the files (.java and your policy file) in a folder d:\java for example.

One console window:
javac *.java -d .
rmic -classpath . Server.serv.RMIExampleImpl
rmiregistry

Second console window:
java -classpath . -Djava.security.policy=policy.all -Djava.rmi.server.codebase=file:///d:/java/ Server.serv.RMIExampleImpl

Third console window:
java -classpath . -Djava.security.policy=policy.all Server.serv.RMIExampleClient

  Hope it helps.
> The problem is with your's codebase

  Yes it was a damn codebase problem.... When in doubt it's alaways classpath :-)
 Btw vsaritha_9 you should reward all the points (this question's and extra points) to msterjev. He helped you the most.
 ... more information. vsaritha_9 when you open each console window you have to go to the folder where you java source files are (d:\java in my computer) in order for it to work.
Thanks girionis!
 You did all of the work. I barely worked on what you constructed :-)
Only one little comment about putting all the files in one folder. In that case everything works, but there a big conceptuall error. The started client actually doesn't download the stub class because it can find in it's own classpath. This is not framework the RMI is intending to be!
Yes i will definitly reward him more than the points which i have opted to give.
But Even after changing my code base, still I am getting same exception.
Hey suggest me shall i accept ur answer or shall i wait untill i get the solution. I will do what u opt for,
I thank Both of you very much
Saritha
> The started client actually doesn't download the stub class because it can find in it's own classpath. This is not framework the RMI is intending to be!

  Yes you are right on this... It first looks on the local classpath and then (if it does not find anything) tries to download the files from a remote location.

  vsaritha_9 since you are still getting the same exception I will try again, thsi time with your own settings. Give me ten more minutes.
ASKER CERTIFIED SOLUTION
Avatar of msterjev
msterjev

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
So, I must go (14:00 - lunch time).
Let the force be with you :-))
yes, i have tried ur code. when i say rimc HelloWorldImpl i m getting error that HelloWorldImpl is not found.
What should i do.. I have taken same folders and filenames which u have given
 Ok here we are again.. sorry for being late I was out for lunch... here is my last sugegstion:

open one window:
put the server and the interface files under a subdirectory (lets say users\saritha\java\exampels\rmi)
compile them:
javac *.java -d .
rmic -classpath . Server.serv.RMIExampleImpl
go to your c drive
rmiregistry

open another window and go to the folder (users\saritha...\rmi)
Run your server with the command you were using.

open another window.
Create a folder (lets say RMItest)
put the client file in there
compile it
run it with the command you were using

  This should run the client and should get the message "saritha"

  If thsi fails as well then stop the registry, set the classpath to point to the users\saritha\java\examples\rmi and restart the rmiregistry, our server and your client.

  Do it and post your results here :-)


Hi

msterjev, I have worked with your code.
It is working fine.
But i am trying to put all the interfaces in one pakage and then import them.
Anyway I will work out with your example

girionis, I have also tried with the example u have given at server side i m getting unmarshall exception.

Thanks a lot.
Have a nice day
Saritha
There is nothing frighting with class packages. I've also write a comment for codebase,check that you write correct the codebase etc. The Final step is working on different machines. Everything is the same, except you will made your's clases public accessible via Web Server, and the java.rmi.server.codebase would be in a http fashion!
Thank you msterjev,
I have got my porblem solved.
I m able to run my program correctly.
Thank you
Saritha