Using Java RMI |
A Note About Security
The JDK1.2 security model is more sophisticated than the model used for JDK1.1. JDK1.2 contains enhancements for finer-grained security and requires code to be granted specific permissions to be allowed to perform certain operations.In JDK1.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 JDK1.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 codebase, to do two things:
- connect to or accept connections on unprivileged ports (ports greater than 1024) on any host, and
- connect to port 80 (the port for HTTP).
If you make your code available for downloading via HTTP URLs, you should use the policy file above when you run this example. However, if you use file URLs instead, you can use the policy file below. 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.net.SocketPermission "*:80", "connect"; };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 contains the appropriate permissions. If you run this example on JDK1.1, you will not need to use a policy file, since theRMISecurityManager
provides all the protection you need.Starting the Server
Before starting the compute engine, you need to start RMI's registry with thermiregistry
command. As discussed earlier in this chapter, 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 the
rmiregistry
, 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 in throughCLASSPATH
, it will not remember that the loaded stub class can be loaded from your server's codebase (that was specified by thejava.rmi.server.codebase
property when you started up your server application). As a result, thermiregistry
will not convey to clients the true codebase associated with the stub class, and consequently, your clients will not be able to locate and 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.The registry, by default, runs on port 1099. To start the registry on a different port, specify the port number on the command line. Don't forget to unset your
Platform-Specific Details: Starting the Registry on Default Port on Host zaphodWindows (use
javaw
ifstart
is not available):unset CLASSPATH start rmiregistryUNIX:
unsetenv CLASSPATH rmiregistry &
CLASSPATH
.
Platform-Specific Details: Starting the Registry on Port 2001Windows:
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.
Platform-Specific Details: Setting the CLASSPATH Environment VariableWindows:
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
andTask
interfaces, available inann
'spublic_html\classes
directory.
Platform-Specific Details: Starting the Compute Engine on Host zaphodWindows:
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
java
command above defines several properties:The
java.rmi.server.codebase
, a property that specifies the location, a codebase 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 codebase specifies a directory (as opposed to a JAR file), you must include the trailing slash in the codebase URL.java.rmi.server.hostname
, a property that 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 hostname. If one cannot be determined, it will fall back and use the IP address. To ensure that RMI will use a hostname that is usable from potential clients, you may want to set thejava.rmi.server.hostname
property as a safety measure.java.security.policy
, a property used to specify the policy file that contains the permissions you intend to grant specific codebases.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.codebase
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 re-loaded for additional references toComputeEngine's
objects.Starting the Client
Once the registry and 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 pi [PENDING: get pi symbol] calculation.java.security.policy
, a property used to specify the policy file that contains the permissions you intend to grant specific codebases.First set the
CLASSPATH to see
jones's client and the JAR file containing the interfaces. Then start the client as follows:
Platform-Specific Details: Starting the Client on Host fordWindows:
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 localhost 20UNIX:
setenv CLASSAPTH /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 figure below illustrates where the
rmiregistry
, theComputeEngine
server and theComputePi
client obtain classes during program execution.The rmiregistry
,ComputeEngine
server andComputePi
obtaining 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
andTask
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 theComputeEngine
's web server, as a result of theNaming.lookup
call. Since theComputePi
client has both theCompute
andTask
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 |