HOME
Java RMI Tutorialpresented with permission by Zi Hiu
IntroductionThis is a brief introduction to Java Remote Method Invocation (RMI). Java RMI is a mechanism that allows one to invoke a method on an object that exists in another address space. The other address space could be on the same machine or a different one. The RMI mechanism is basically an object-oriented RPC mechanism. CORBA is another object-oriented RPC mechanism. CORBA differs from Java RMI in a number of ways:
Java RMI has recently been evolving toward becoming more compatible with CORBA. In particular, there is now a form of RMI called RMI/IIOP ("RMI over IIOP") that uses the Internet Inter-ORB Protocol (IIOP) of CORBA as the underlying protocol for RMI communication. This tutorial attempts to show the essence of RMI, without discussing any extraneous features. Sun has provided a Guide to RMI, but it includes a lot of material that is not relevant to RMI itself. For example, it discusses how to incorporate RMI into an Applet, how to use packages and how to place compiled classes in a different directory than the source code. All of these are interesting in themselves, but they have nothing at all to do with RMI. As a result, Sun's guide is unnecessarily confusing. Moreover, Sun's guide and examples omit a number of details that are important for RMI. There are three processes that participate in supporting remote method invocation.
In this tutorial, we will give an example of a Client and a Server that solve the classical "Hello, world!" problem. You should try extracting the code that is presented and running it on your own computer. There are two kinds of classes that can be used in Java RMI.
Serializable Classes
We now consider how to design Remote and Serializable classes.
The easier of the two is a Serializable class.
A class is Serializable if it implements the Using a serializable object in a remote method invocation is straightforward. One simply passes the object using a parameter or as the return value. The type of the parameter or return value is the Serializable class. Note that both the Client and Server programs must have access to the definition of any Serializable class that is being used. If the Client and Server programs are on different machines, then class definitions of Serializable classes may have to be downloaded from one machine to the other. Such a download could violate system security. This problem is discussed in the Security section. The only Serializable class that will be used in the "Hello, world!" example is the String class, so no problems with security arise.
Remote Classes and InterfacesNext consider how to define a Remote class. This is more difficult than defining a Serializable class. A Remote class has two parts: the interface and the class itself. The Remote interface must have the following properties:
In the example program, we need a Remote class and its corresponding
Remote interface. We call these import java.rmi.*;
/**
* Remote Interface for the "Hello, world!" example.
*/
public interface HelloInterface extends Remote {
/**
* Remotely invocable method.
* @return the message of the remote object, such as "Hello, world!".
* @exception RemoteException if the remote invocation fails.
*/
public String say() throws RemoteException;
}
Here is the file Hello.java:
import java.rmi.*;
import java.rmi.server.*;
/**
* Remote Class for the "Hello, world!" example.
*/
public class Hello extends UnicastRemoteObject implements HelloInterface {
private String message;
/**
* Construct a remote object
* @param msg the message of the remote object, such as "Hello, world!".
* @exception RemoteException if the object handle cannot be constructed.
*/
public Hello (String msg) throws RemoteException {
message = msg;
}
/**
* Implementation of the remotely invocable method.
* @return the message of the remote object, such as "Hello, world!".
* @exception RemoteException if the remote invocation fails.
*/
public String say() throws RemoteException {
return message;
}
}
All of the Remote interfaces and classes should be compiled using
rmic Hello
The only problem one might encounter with this command is that
setenv CLASSPATH .If your CLASSPATH variable already has some directories
in it, then you might want to add the current directory to the others.
Programming a ClientHaving described how to define Remote and Serializable classes, we now discuss how to program the Client and Server. The Client itself is just a Java program. It need not be part of a Remote or Serializable class, although it will use Remote and Serializable classes. A remote method invocation can return a remote object as its return value, but one must have a remote object in order to perform a remote method invocation. So to obtain a remote object one must already have one. Accordingly, there must be a separate mechanism for obtaining the first remote object. The Object Registry fulfills this requirement. It allows one to obtain a remote object using only the name of the remote object. The name of a remote object includes the following information:
/**
* Client program for the "Hello, world!" example.
* @param argv The command line arguments which are ignored.
*/
public static void main (String[] argv) {
try {
HelloInterface hello =
(HelloInterface) Naming.lookup ("//ortles.ccs.neu.edu/Hello");
System.out.println (hello.say());
} catch (Exception e) {
System.out.println ("HelloClient exception: " + e);
}
}
The
The remote method invocation in the example Client is
The code for the Client can be placed in any convenient class.
In the example Client, it was placed in a class
Programming a ServerThe Server itself is just a Java program. It need not be a Remote or Serializable class, although it will use them. The Server does have some responsibilities:
/**
* Server program for the "Hello, world!" example.
* @param argv The command line arguments which are ignored.
*/
public static void main (String[] argv) {
try {
Naming.rebind ("Hello", new Hello ("Hello, world!"));
System.out.println ("Hello Server is ready.");
} catch (Exception e) {
System.out.println ("Hello Server failed: " + e);
}
}
The rmiregistry Object Registry only accepts requests
to bind and unbind objects running on the same machine,
so it is never necessary to
specify the name of the machine when one is registering an object.
The code for the Server can be placed in any convenient class.
In the example Server, it was placed in a class
Starting the ServerBefore starting the Server, one should first start the Object Registry, and leave it running in the background. One performs this by using the command: rmiregistry &It takes a second or so for the Object Registry to start running and to start listening on its socket. If one is using a script, then one should program a pause after starting the Object Registry. If one is typing at the command line, it is unlikely that one could type fast enough to get ahead of the Object Registry. The Server should then be started; and, like the Object Registry, left running in the background. The example Server is started using the command: java HelloServer &The Server will take a few seconds to start running, and to construct and register remote objects. So one should wait a few seconds before running any Clients. Printing a suitable message, as in the example Server, is helpful for determining when the Server is ready.
Running a ClientTh Client is run like any other java program. The example Client is executed using: java HelloClient
For this to run it is necessary for the HelloClient, HelloInterface
and Hello_Stub classes be available on the client machine. In particular,
the In theory, it should be possible for the client to download the necessary class files from the server without the need for these classes to be on the client machine. In practice, this is very difficult to accomplish because classes can use other classes in other packages, and these other packages are determined by the CLASSPATH which is locally defined on each machine. More sophisticated (and more complex) remote method invocation mechanisms (such as CORBA) can achieve this, but simpler mechanisms like RMI cannot (at least not yet).
SecurityOne of the most common problems one encounters with RMI is a failure due to security constraints. This section gives a very brief introduction to the Java security model as it relates to RMI. For a more complete treatment, one should read the documentation for the Java SecurityManager and Policy classes and their related classes. Note that this section assumes that one is using Java 1.2 or later. Some of the statements are not true for earlier versions.
A Java program may specify a security manager that determines
its security policy. A program will not have any security manager
unless one is specified.
One sets the security policy by constructing a SecurityManager object and
calling the However, many Java installations have instituted security policies that are more restrictive than the default. There are good reasons for instituting such policies, and one should not override them carelessly. The rest of this section discusses some ways that can be used for overriding security policies that prevent RMI from functioning properly.
The SecurityManager class has a large number of methods
whose name begins with java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve)The message above would occur when an RMI server or client was not allowed to connect to the RMI registry running on the same machine as the server or client.
As discussed above, one sets the security policy by passing an object of type
SecurityManager to the setSecurityManager method of the System class. There
are several ways to modify the security policy of a program. The simplest
technique is to define a subclass of SecurityManager and to call
The following code illustrates how to do this:
System.setSecurityManager (new RMISecurityManager() {
public void checkConnect (String host, int port) {}
public void checkConnect (String host, int port, Object context) {}
});
The code above uses an anonymous inner class. Such a class is convenient when the class will only be used to construct an object in one place, as in this example. Of course, one could also define the subclass of RMISecurityManager in the usual way.
Defining and installing a security manager was the original technique
for specifying a security policy in Java. Unfortunately, it is very
difficult to design such a class so that it does not leave any security
holes. For this reason, a new technique was introduced in Java 1.2,
which is backward compatible with the old technique.
In the default security manager, all check methods
(except
This is the mechanism whereby the security manager checks permissions,
but it does not explain how one specifies or changes the security policy.
For this purpose there is yet another class, named Policy.
Like SecurityManager, each program has a current security policy
that can be obtained by calling grant codeBase "file:C:/RMI/-" {
permission java.security.AllPermission;
};
The default security manager uses a policy that is defined in a collection
of policy files. For the locations of these files see the documentation
of the java -Djava.security.manager -Djava.security.policy=policy-file MyClassBoth of the "-D" options specify system properties. The first system property has the same effect as executing the following statement as the first statement in your program: System.setSecurityManager (new SecurityManager());The second system property above causes the specified policy-file (which is specified with a URL) to be added to the other policy files when defining the entire security policy. The policytool can be used to construct the policy file,
but one can also use any text editor.
As if this wasn't already complicated enough,
there is yet another way to deal with the problem of downloading
Serializable classes.
The command-line option
Linux Google Amazon Web Server Programming Windows Web (webmastering) Mix Computer related text Microsoft Word |