Basic Beginner Question about RMI
I am trying to use RMI and am getting confused about something about how to bind ("rebind") names into the RMI registry.
The RMI Java Turtorial -- Implementing a Remote Interface(http://java.sun.com/docs/books/tutorial/rmi/implementing.html) states the following:
"
Note the following about the arguments to the call to Naming.rebind.
The first parameter is a URL-formatted java.lang.String representing the location and the name of the remote object. You will need to change the value of host to be the name, or IP address, of your server machine. If the host is omitted from the URL, the host defaults to the local host. Also, you don't need to specify a protocol in the URL. For example, supplying Compute as the name in the Naming.rebind call is allowed. Optionally a port number may be supplied in the URL; for example, the name //host:1234/objectname is legal. If the port is omitted, it defaults to 1099. You must specify the port number only if a server creates a registry on a port other than the default 1099. The default port is useful in that it provides a well-known place to look for the remote objects that offer services on a particular host.
The RMI runtime substitutes a reference to the stub for the remote object reference specified by the argument. Remote implementation objects, such as instances of ComputeEngine, never leave the VM where they are created, so when a client performs a lookup in a server's remote object registry, a reference to the stub is returned. As discussed earlier, remote objects in such cases are passed by reference rather than by value.
Note that for security reasons, an application can bind, unbind, or rebind remote object references only with a registry running on the same host. This restriction prevents a remote client from removing or overwriting any of the entries in a server's registry. A lookup, however, can be requested from any host, local or remote.
"
What I don't understand is why you should ever supply a host in a "rebind" call since it says that for security reasons an application can rebind only on the same host and since it says that omitting the host causes the host to default to the local host. Also, if I am correct that there is never any reason to supply a host name in a "rebind" call, then why is it so **** hard to find an actual example of a "rebind" without the host name in it? In other words, what is the proper way to leave out the host name from the following URL: "//host/Compute"? Is it "///Compute", "//Compute", "/Compute", "Compute" or something else or does more than one form work?
I appreciate your help.
P.S. While I am asking RMI questions, another one just came to mind. Can someone give me an example of using RMI in the simplest possible way, that is for only Remote Method calls with absolutely no downloading or uploading of any classes or anything else? I want to use RMI without a security manager installed, in other words. The code on the client machine will be identical to the code on the server machine, but I need the client to access a database on the server using a remote method call. I can't seem to get it to work this way. Again, not using a security manager is an absolute requirement.
Thanks !!!
[3298 byte] By [
j.malonea] at [2007-10-3 4:19:32]

I think the reason was to allow rebinding by remote hosts, by using a more permissive SecurityManager. I would not recommend it though; unless you are working in a highly trusted, and well protected network.
As for an example of using RMI in the simplest possible way; I really think [url=http://wiki.java.net/bin/view/Communications/TransparentProxy]this is it![/url]
Of course I might be a little biased; I did write the example... ;-)
Good luck,
John
cajoa at 2007-7-14 22:21:23 >

Thanks, John. I appreciate your desire to help and that you have written a nice way to utilize remote objects without having to understand what you are really doing. However, I want to understand at this point, not to use someone else's code without understanding.
Your usage may in fact be simple, but isolating the few lines of simple code that actually do what I want to do by looking at your web site is not a simple task. (I spent a couple of hours and did not get very far). Again, I am not in a position at this point where I can simply take what you have written and use it -- I need to understand RMI and write my own code at this point.
Your short response did seem to partially confirm my suspicion that almost all the time (if not all the time) when a name is bound to the RMI registry the call to "rebind" can (and probably should) omit the name of the host since you are binding on the local host. (It is very frustrating to me that no one ever seems to give an example of binding without specifying the host name.)
I am going to number my questions so readers can easily keep up with what has been answered and what has not:
1) I still do not know the proper form of the URL with the host name left out of it. Could someone tell me how to leave the hostname out of the following URL: "//hostname/BindingName"? (Some guesses are: "///BindingName", "//BindingName", "/BindingName", and "BindingName".)
2) Could someone supply a few lines of server side code that properly binds a name into a RMI registry without using the host or port name and a few lines of client side code that lookup this object and make a remote method call on it? Remember, please do not have a security manager installed (all stubs and classes are on client as well as server.) It would be 10 times more helpful to me if you can say that you have verified that this code actually works (you tested it), since I will be extrapolating from your code to my own implementation -- if there is the possibility of bugs in your code, that brings a lot of uncertainty to my own debugging process.
3) Also, I remember reading something in the last few days that said you could list the names that are bound to the RMI resgistry, but I don't know how to do this. Could someone out there tell me how to list the contents of the RMI registry?
Again thanks for your help !
Addressing your first post, the answer to question #1 is that the only sensible way to write Naming.bind/rebind/unbind calls is by specifying 'localhost' as the hostname. It can't be anything else. Only the Naming.list() and Naming.lookup() calls need real hostnames.
The hostname is there in the argument for symmetry with the list and lookup calls, and also to allow for the possibility of more elaborate Registries with security policies for bind/rebind/unbind that don't just restrict callers to the localhost (such as in my RMIProxy product for example).
The answer to your second question is that the Registry always needs access to the stubs and remote interfaces and anything else that they refer to, so when not using a codebase system it is essential that these are on the Registry's classpath. So you generally have a setup where the server jar has the remote method implementations, the client jar has its own stuff, and there is a common.jar which contains the stubs and remote interfaces and their closure in terms of other classes. This common.jar needs to be on the Registry's classpath as well as the client's and the server's.
Addressing your second post
1. The rules are the same as for a URL. I believe any of ///BindingName and /BindingName and BindingName should work. Try it! //BindingName won't work: it is the hostname syntax.
2. Naming.rebind("BindingName", new MyRemoteObject(...));
I must say that I never abbreviate these things. I would always writeNaming.rebind("rmi://localhost/BindingName", new ...) ;
because I know it works and it's clearer IMHO.
3. String[] bindings = Naming.list("rmi://hostname");
ejpa at 2007-7-14 22:21:23 >

Okay, thank you... I very much appreciate your help. Sorry to have to do this, but I just can't get RMI working, so I need someone to help me debug a simple application until I learn enough.
I tried the following code to test what you told me. Three simple little files:
RMITest.java:
import java.rmi.Naming;
public class RMITest {
public static void main(String[] args) throws Exception {
System.err.println("Before first rebind...");
Naming.rebind("rmi://localhost/test1",new MyRemoteClass("Test1"));
System.err.println("Before second rebind...");
Naming.rebind("rmi://localhost/test2",new MyRemoteClass("Test2"));
System.err.println("Before list...");
System.out.println(Naming.list("rmi://localhost"));
}
}
MyRemoteInterface.java:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyRemoteInterface extends Remote {
public String doit() throws RemoteException;
}
and MyRemoteClass.java:
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
public class MyRemoteClass extends UnicastRemoteObject implements MyRemoteInterface {
String text;
MyRemoteClass() throws RemoteException {
super();
}
MyRemoteClass(String text) throws RemoteException {
super();
this.text = text;
}
public String doit() throws RemoteException {
return "Text: #"+text+"#";
}
}
javac RMITest.javagives no errors and generates the class files.
with RMIRegistry running,
java RMITestgives the following:
Before first rebind...
Exception in thread "main" java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: MyRemoteInterface
at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:385)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:240)
<<... etc.... let me know if you need more of the error>>
This is the kind of thing I have been getting with RMI for the last couple of weeks and I am getting very frustated. Can you please help me? I have been trying really hard to learn this stuff, but I just can't seem to get it working. It is probably silly stuff I am doing wrong, but I feel I am applying everything I have read, and I have read a lot.
Yep. This is all addressed in my third paragraph above.
In this case the Registry can't find the remote interface although it seems to have found the stub. Further down the stack trace I would expect to see Naming.rebind().
The server needs:
- the impl class
- the remote interface
- the stub
The Registry and client both need
- the remote interface
- the stub
There are three cases of the ClassNotFoundException problem with three different causes, which causes confusion:
1. During export. The server can't find the stub.
2. During Naming.rebind(). The Registry can't find the stub, or the remote interface, or another class that the stub depends on.
3. During Naming.lookup(). Same as (2) reading 'client' instead of 'Registry'.
If this continues to give you grief can I recommend my book 'java.rmi: The Guide to Remote Method Invocation'? It contains a chapter explaining every RMI exception and how it can happen, including the above, in complete and relentless detail.
ejpa at 2007-7-14 22:21:23 >

Yes, thanks... I suppose it was covered in your thrid paragraph, but I guess the jar stuff seemed a little overkill for this simple case. As a matter of fact, I was able to get past the problem by simply starting the RMIRegistry from the directory that contained the classes, though for my full application, I will probably need to do things more along the lines that you suggested in your third paragraph.
I am now getting an error with the following client:
import java.rmi.Naming;
public class MyClient {
public static void main(String[] args) throws Exception {
MyRemoteInterface remoteProxy1 = (MyRemoteClass)Naming.lookup("rmi://localhost/test1");
MyRemoteInterface remoteProxy2 = (MyRemoteClass)Naming.lookup("rmi://localhost/test2");
remoteProxy1.doit();
remoteProxy2.doit();
}
}
It gives the following error:
Exception in thread "main" java.lang.ClassCastException: MyRemoteClass_Stub
at MyClient.main(MyClient.java:4)
which I guess indicates that there is something wrong with casting the Naming.lookup(...) result back to MyRemoteClass. What am I doing wrong now?
Correct. The object returned by lookup isn't an instance of MyRemoteClass, is it? Because that's back at the server. It's an instance of MyRemoteInterface.
ejpa at 2007-7-14 22:21:23 >

To understand better iam writing the sample RMI Application.
Inorder to develop the RMI application you need to have the following things:
1.A remote interface
2.Implementation class
3.Server application
4.client Application
// 1 A remote interface
public interface StudentInterface extends java.rmi.Remote {
public void setRollNumber(int rollNum) throws java.rmi.RemoteException;
public int getRollNumber() throws java.rmi.RemoteException;
}
// 2 Implementation class
public class StudentImpl extends java.rmi.server.UnicastRemoteException implements StudentInterface {
private int rollNumber;
public StudentImpl() throws java.rmi.RemoteException {}
public void setRollNumber(int rollNumber) {
this.rollNumber=rollNumber;
}
public int getRollNumber() {
return this.rollNumber;
}
}
// Server application
public class ServerApp {
public static void main(String args[]) throws Exception {
StudentImpl stimpl=new StudentImpl();
java.naming.Naming.rebind("<uri>",stimpl);
System.out.println("Server is running...");
}
}
// Client Application
public class ClientApp {
public static void main(String args[]) throws Exception {
StudentInterface stuobj=(StudentInterface) java.naming.lookup("<uri>");
studobj.setRollNumber(1000);
System.out.println("My roll number is "+studobj.getRollNumber());
}
}
Association of name to an object is called Binding which can be done through java.naming.bind()
over riding the existing name with the new name is called rebinding which can be done through java.rmi.rebind()
