Using Java RMI |
A Note about Security
The JDK 1.2 security model is more sophisticated than the model used for JDK 1.1. JDK 1.2 contains enhancements for finer-grained security and requires code to be granted specific permissions to be allowed to perform certain operations.In JDK 1.1 code in the class path is trusted and can perform any operation; downloaded code is governed by the rules of the installed security manager. If you run this example in JDK 1.2, you need to specify a policy file when you run your server and client. Here is a general policy file that allows downloaded code, from any code base, to do two things:
- Connect to or accept connections on unprivileged ports (ports greater than 1024) on any host
- Connect to port 80 (the port for HTTP)
Here is the code for the general policy file:
grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept"; permission java.net.SocketPermission "*:80", "connect"; };If you make your code available for downloading via HTTP URLs, you should use the preceding policy file when you run this example. However, if you use file URLs instead, you can use the following policy file. Note that in Windows-style file names, the backslash character needs to be represented by two backslash characters in the policy file.
grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept"; permission java.io.FilePermission "c:\\home\\ann\\public_html\\classes\\-", "read"; permission java.io.FilePermission "c:\\home\\jones\\public_html\\classes\\-", "read"; };This example assumes that the policy file is called
java.policy
and that it contains the appropriate permissions. If you run this example on JDK 1.1, you will not need to use a policy file, since theRMISecurityManager
provides all of the protection you need.Start the Server
Before starting the compute engine, you need to start RMI's registry, using thermiregistry
command. As discussed earlier, the RMI registry is a simple server-side bootstrap naming facility that allows remote clients to get a reference to a remote object. Note that before you start thermiregistry
, you must make sure that the shell or window in which you will runrmiregistry
either has noCLASSPATH
environment variable set or has aCLASSPATH
environment variable that does not include the path to any classes, including the stubs for your remote object implementation classes, that you want downloaded to clients of your remote objects.If you do start the
rmiregistry
and it can find your stub classes inCLASSPATH
, it will not remember that the loaded stub class can be loaded from your server's code base, specified by thejava.rmi.server.codebase
property when you started up your server application. Therefore, thermiregistry
will not convey to clients the true code base associated with the stub class and, consequently, your clients will not be able to locate and to load the stub class or other server-side classes.To start the registry on the server, execute the
rmiregistry
command. This command produces no output and is typically run in the background. For this example, we will start the registry on the hostzaphod
.
Win32 (use javaw
ifstart
is not available): unset CLASSPATH start rmiregistryUNIX: unsetenv CLASSPATH rmiregistry &
By default, the registry runs on port 1099. To start the registry on a different port, specify the port number on the command line. Do not forget to unset your
CLASSPATH
.
Win32: start rmiregistry 2001UNIX: rmiregistry 2001 &
Once the registry is started, you can start the server. First, you need to make sure that both the
compute.jar
file and the remote object implementation class (since that is what you are starting) are in your class path.
Win32: set CLASSPATH=c:\home\ann\src;c:\home\ann\public_html\classes\compute.jarUNIX: setenv CLASSPATH /home/ann/src:/home/ann/public_html/classes/compute.jar
When you start the compute engine, you need to specify, using the
java.rmi.server.codebase
property, where the server's classes will be made available. In this example the server-side classes to be made available for downloading are theComputeEngine
's stub and theCompute
and theTask
interfaces, available inann
'spublic_html\classes
directory. Here, we start the compute engine server on the hostzaphod
, the same host where we started the registry.
Win32: java -Djava.rmi.server.codebase=file:/c:\home\ann\public_html\classes/ -Djava.rmi.server.hostname=zaphod.east.sun.com -Djava.security.policy=java.policy engine.ComputeEngineUNIX: java -Djava.rmi.server.codebase=http://zaphod/~ann/classes/ -Djava.rmi.server.hostname=zaphod.east.sun.com -Djava.security.policy=java.policy engine.ComputeEngine
The preceding
java
command defines several properties.
- The
java.rmi.server.codebase
property specifies the location, a code base URL, of classes originating from this server so that class information for objects sent to other virtual machines will include the location of the class so that a receiver can load it. If the code base specifies a directory (as opposed to a JAR file), you must include the trailing slash in the code base URL.- The
java.rmi.server.hostname
property indicates the fully qualified host name of your server. In some networked environments a fully qualified host name is not obtainable by using the Java APIs. RMI makes a best-effort attempt to obtain the fully qualified host name. If one cannot be determined, it will fall back and use the IP address. To ensure that RMI will use a host name that is usable from potential clients, you may want to set thejava.rmi.server.hostname
property as a safety measure.- The
java.security.policy
property is used to specify the policy file that contains the permissions you intend to grant specific code bases.The
ComputeEngine
's stub class is dynamically loaded into a client's virtual machine only when the class is not already available locally and thejava.rmi.server.codebas
e property has been set properly, to the network-accessible location of the stub class, when the server is started. Once such a stub is loaded, it will not need to be reloaded for additional references toCom-puteEngine
's objects.Start the Client
Once the registry and the engine are running, you can start the client, specifying
- The location where the client serves up its classes (the
Pi
class), using thejava.rmi.server.codebase
property- As command line arguments the host name of the server--so that the client knows where to locate the
Compute
remote object--and the number of decimal places to use in the calculation- The
java.security.policy
property, used to specify the policy file that contains the permissions you intend to grant specific code basesFirst, set the
CLASSPATH
to seejones
's client and the JAR file containing the interfaces. Then start the client on another host (one namedford
, for example) as follows:
Win32: set CLASSPATH c:\home\jones\src;c:\home\jones\public_html\classes\compute.jar java -Djava.rmi.server.codebase=file:/c:\home\jones\public_html\classes/ -Djava.security.policy=java.policy client.ComputePi zaphod.east.sun.com 20UNIX: setenv CLASSPATH /home/jones/src:/home/jones/public_html/classes/compute.jar java -Djava.rmi.server.codebase=http://ford/~jones/classes/ -Djava.security.policy=java.policy client.ComputePi zaphod.east.sun.com 20
Note that the class path is set on the command line so that the interpreter can find
jones
's client and the JAR file containing the interfaces.After starting the client, you should see the following output on your display:
3.14159265358979323846The following figure illustrates where the
rmiregistry
, theComputeEngine
server, and theComputePi
client obtain classes during program execution.When the
ComputeEngine
server binds its remote object reference in the registry, the registry downloads theComputeEngine_Stub
, as well as theCompute
and theTask
interfaces on which the stub class depends. These classes are downloaded from theComputeEngine
's web server or file system, as the case may be.The
ComputePi
client loads theComputeEngine_Stub
, also from theCompute-Engine
's web server, as a result of theNaming.lookup
call. Since theComputePi
client has both theCompute
and theTask
interfaces available in its class path, those classes are loaded from the class path, not the remote location.Finally, the
Pi
class is loaded into theComputeEngine
's virtual machine when thePi
object is passed in theexecuteTask
remote call to theComputeEngine
object. ThePi
class is loaded from the client's web server.
Using Java RMI |