Академический Документы
Профессиональный Документы
Культура Документы
The distributed Hello World example uses an applet to make a remote method call to an RMI server, running on the
host from which the applet was downloaded. When the applet runs, "Hello World!" is displayed on the client
browser.
1. The steps to write the source files and the HTML file
2. The steps to compile and deploy class files and the HTML file
3. The steps to start the RMI registry, server, and applet
Note: For the remainder of this tutorial, the terms "remote object implementation," "object implementation," and
"implementation" may be used interchangeably to refer to the class, examples.hello.HelloImpl, which
implements a remote interface.
For all of the source code used in this tutorial, you may choose from the following formats:
getStart.zip
getStart.tar
getStart.tar.Z
To create the directory for your source files in the SolarisTM operating environment, execute the command:
mkdir -p $HOME/mysrc/examples/hello
On Microsoft Windows platforms, you would go to the directory of your choice, and type:
mkdir mysrc
mkdir mysrc\examples
mkdir mysrc\examples\hello
1. Define the functions of the remote class as an interface written in the Java programming language
2. Write the implementation and server classes
3. Write a client program that uses the remote service
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 1/11
1/9/2019 Getting Started Using RMI
The remote interface must be declared public. Otherwise, a client will get an error when attempting to load a
remote object that implements the remote interface, unless that client is in the same package as the remote
interface.
The remote interface extends the java.rmi.Remote interface.
Each method must declare java.rmi.RemoteException (or a superclass of RemoteException) in its throws
clause, in addition to any application-specific exceptions.
The data type of any remote object that is passed as an argument or return value (either directly or embedded
within a local object) must be declared as the remote interface type (for example, Hello) not the
implementation class (HelloImpl).
Here is the interface definition for the remote interface, examples.hello.Hello. The interface contains just one
method, sayHello, which returns a string to the caller:
package examples.hello;
import java.rmi.Remote;
import java.rmi.RemoteException;
Because remote method invocations can fail in very different ways from local method invocations (due to network-
related communication problems and server problems), remote methods will report communication failures by
throwing a java.rmi.RemoteException. If you want more information on failure and recovery in distributed
systems, you may wish to read A Note on Distributed Computing.
A "server" class, in this context, is the class which has a main method that creates an instance of the remote object
implementation, and binds that instance to a name in the rmiregistry. The class that contains this main method
could be the implementation class itself, or another class entirely.
In this example, the main method is part of examples.hello.HelloImpl. The server program needs to:
An explanation of each of the preceding six steps follows the source for HelloImpl.java:
package examples.hello;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 2/11
1/9/2019 Getting Started Using RMI
public HelloImpl() throws RemoteException {
super();
}
try {
HelloImpl obj = new HelloImpl();
As a convenience, the implementation class can extend a remote class, which in this example is
java.rmi.server.UnicastRemoteObject. By extending UnicastRemoteObject, the HelloImpl class
can be used to create a remote object that:
If you want a remote object that can be activated (created) when a client requests it, rather than running
all the time, after you finish this tutorial, you can take a look at the RMI Activation tutorial. Also, you
can learn about how to use your own communication protocol, rather than the TCP sockets that RMI
uses by default, in the tutorial on Using a Custom RMI Socket Factory.
The constructor for a remote class provides the same functionality as the constructor for a non-remote
class: it initializes the variables of each newly created instance of the class, and returns an instance of
the class to the program which called the constructor.
In addition, the remote object instance will need to be "exported". Exporting a remote object makes it
available to accept incoming remote method requests, by listening for incoming calls to the remote
object on an anonymous port. When you extend java.rmi.server.UnicastRemoteObject or
java.rmi.activation.Activatable, your class will be exported automatically upon creation.
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 3/11
1/9/2019 Getting Started Using RMI
If you choose to extend a remote object from any class other than UnicastRemoteObject or
Activatable, you will need to explicitly export the remote object by calling either the
UnicastRemoteObject.exportObject method or the Activatable.exportObject method from your
class's constructor (or another initialization method, as appropriate).
Because the object export could potentially throw a java.rmi.RemoteException, you must define a
constructor that throws a RemoteException, even if the constructor does nothing else. If you forget the
constructor, javac will produce the following error message:
If you are interested in why java.rmi.RemoteException is a checked exception rather than runtime
exception, please refer to the archives of the rmi-users email list:
http://archives.java.sun.com/archives/rmi-users.html
Although the call to the superclass's no-argument constructor, super(), occurs by default (even if
omitted), it is included in this example to make clear the fact that the Java virtual machine (JVM)
constructs the superclass before the class.
Arguments to, or return values from, remote methods can be any data type for the Java platform,
including objects, as long as those objects implement the interface java.io.Serializable. Most of
the core classes in java.lang and java.util implement the Serializable interface. In RMI:
By default, local objects are passed by copy, which means that all data members (or fields) of an
object are copied, except those marked as static or transient. Please refer to the Java Object
Serialization Specification for information on how to alter the default serialization behavior.
Remote objects are passed by reference. A reference to a remote object is actually a reference to
a stub, which is a client-side proxy for the remote object. Stubs are described fully in the Java
Remote Method Invocation Specification. We'll create them later in this tutorial in the section:
Use rmic to generate stubs and skeletons.
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 4/11
1/9/2019 Getting Started Using RMI
A class can define methods not specified in the remote interface, but those methods can only be invoked
within the virtual machine running the service and cannot be invoked remotely.
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
A security manager needs to be running so that it can guarantee that the classes that get loaded do not
perform operations that they are not allowed to perform. If no security manager is specified no class
loading, by RMI clients or servers, is allowed, aside from what can be found in the local CLASSPATH.
In this example, a security manager is not installed in the client code because applets use the security
manager already installed in the client browser. If the client were an application rather than an applet,
however, you would need to use the same procedure as is used above to install a security manager in
the client. A security manager is required in any JVM that needs to download code, and RMI clients
need to download RMI stubs (as well as any other custom classes or interfaces needed to communicate
with the RMI server).
The main method of the server needs to create one or more instances of the remote object
implementation which provides the service. For example:
HelloImpl obj = new HelloImpl();
The constructor exports the remote object, which means that once created, the remote object is ready to
accept incoming calls.
For bootstrapping, the RMI system provides a remote object registry that allows you to bind a URL-
formatted name of the form "//host/objectname" to the remote object, where objectname is a simple
string name.
The RMI registry is a simple server-side name service that allows remote clients to get a reference to a
remote object. It is typically used only to locate the first remote object an RMI client needs to talk to.
Then that first object would in turn provide application-specific support for finding other objects.
For example, the reference can be obtained as a parameter to, or a return value from, another remote
method call. For a discussion on how this works, please take a look at Applying the Factory Pattern to
RMI.
Once a remote object is registered on the server, callers can look up the object by name, obtain a
remote object reference, and then remotely invoke methods on the object.
For example, the following code binds the name "HelloServer" to a reference for the remote object:
Naming.rebind("//myhost/HelloServer", obj);
Note the following about the arguments to the rebind method call:
The first parameter is a URL-formatted java.lang.String, representing the location and name
of the remote object.
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 5/11
1/9/2019 Getting Started Using RMI
You will need to change the value of myhost to be the name or IP address of your server
machine; otherwise, the remote object host defaults to the current host. For example,
"HelloServer" is a valid name string that refers to a remote object bound to the name
HelloServer, running on the local host.
Optionally, a port number can be supplied in the URL-formatted string. Specifying the port
number is necessary when the registry that needs to be contacted is running on a port other
than the default port, 1099. For example, "//myhost:1234/HelloServer" is a valid name
string for the HelloServer remote object, reachable through an RMI registry that is
running on the host myhost and is listening for incoming calls on port 1234.
The second parameter is a reference to the object implementation, on which remote methods will
be invoked.
Once an object is exported, the RMI runtime substitutes a reference to the remote object's stub
for the actual remote object reference specified by the obj argument. When a client performs a
lookup in a server's remote object registry, a serialized instance of the stub for the
implementation is returned.
For security reasons, an application can bind or unbind only to a registry running on the same host.
This prevents a client from removing or overwriting any of the entries in a server's remote registry. A
lookup, however, can be done from any host.
package examples.hello;
import java.applet.Applet;
import java.awt.Graphics;
import java.rmi.Naming;
import java.rmi.RemoteException;
1. First, the applet gets a reference to the remote object implementation (advertised as "HelloServer") from the
server host's rmiregistry. Like the Naming.rebind method, the Naming.lookup method takes a URL-
formatted java.lang.String. In this example, the applet constructs the URL string by using the
getCodeBase method in conjunction with the getHost method. Naming.lookup takes care of the following
tasks:
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 6/11
1/9/2019 Getting Started Using RMI
Constructing a registry stub instance (to contact the server's registry) using the hostname and port
number supplied as arguments to Naming.lookup
Using the registry stub to call the remote lookup method on the registry, using the URL's name
component ("HelloServer")
2. The applet invokes the remote sayHello method on the server's remote object
3. The applet invokes the paint method, causing the string "Hello World!" to be displayed in the drawing area
of the applet.
The URL-formatted string that is passed as a parameter to the Naming.lookup method must include the server's
hostname. Otherwise, the applet's lookup attempt will default to the client, and the AppletSecurityManager will
throw an exception because the applet cannot access the local system, but is instead limited to only communicating
with the applet's host.
Here is the HTML code for the web page that references the Hello World applet:
<HTML>
<title>Hello World</title>
<center> <h1>Hello World</h1> </center>
<applet codebase="myclasses/"
code="examples.hello.HelloApplet"
width=500 height=120>
</applet>
</HTML>
There needs to be an HTTP server running on the machine from which you want to download classes.
The codebase in the HTML file specifies a directory below the directory from which the web page was itself
loaded. Using this kind of relative path is usually a good idea. For example, if the codebase directory (where
the applet's class files live), referenced by the applet's HTML, was in the directory above the the HTML
directory, you would use the relative path, "../".
The applet's code attribute specifies the fully-qualified package name of the applet, in this example
examples.hello.HelloApplet:
code="examples.hello.HelloApplet"
Hello.java contains the source code for the Hello remote interface
HelloImpl.java contains the source code for the HelloImpl remote object implementation and the RMI
server for the applet
HelloApplet.java contains the source code for the applet
hello.html is the web page that references the Hello World applet.
In this section, you compile the .java source files to create .class files. You then run the rmic compiler to create
stubs and skeletons. A stub is a client-side proxy for a remote object which forwards RMI calls to the server-side
dispatcher, which in turn forwards the call to the actual remote object implementation.
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 7/11
1/9/2019 Getting Started Using RMI
When you use the javac and rmic compilers, you must specify where the resulting class files should reside. For
applets, all files should be in the applet's codebase directory. For our example, this directory is
$HOME/public_html/myclasses.
Some web servers allow accessing a user's public_html directory via an HTTP URL constructed as
"http://host/~username/". If your web server does not support this convention, you could use a file URL of the
form "file:/home/username/public_html" for testing, but this approach will limit you to communicating
between a client and server that have access to the same physical file system. As an alternative, you can use an
HTTP URL by setting up a minimal web server on your system; we have one available for download here.
This command creates the directory examples/hello (if it does not already exist) in the directory
$HOME/public_html/myclasses. The command then writes to that directory the files Hello.class,
HelloImpl.class, and HelloApplet.class. These are the remote interface, the implementation, and
the applet respectively. For an explanation of javac options, you can refer to the Solaris javac manual
page or the Windows javac manual page.
By default, in the Java 2 SDK, v1.2 and later, rmic runs with the -vcompat flag on, which produces
stubs and skeletons that support access to:
If you will never need support for 1.1 clients, rmic can be run with the -v1.2 option. For an
explanation of rmic options, you can refer to the Solaris rmic manual page or the Windows rmic
manual page.
For example, to create the stub and skeleton for the HelloImpl remote object implementation, run rmic
like this:
The "-d" option indicates the root directory in which to place the compiled stub and skeleton class
files. So the preceding command creates the following files in the directory
$HOME/public_html/myclasses/examples/hello:
HelloImpl_Stub.class
HelloImpl_Skel.class
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 8/11
1/9/2019 Getting Started Using RMI
The generated stub class implements exactly the same set of remote interfaces as the remote object
itself. This means that a client can use the Java programming language's built-in operators for casting
and type checking. It also means that remote objects written for the Java platform support true object-
oriented polymorphism.
Note: Before you start the rmiregistry, you must make sure that the shell or window in which you will
run the registry either has no CLASSPATH set or has a CLASSPATH that does not include the path to
any classes that you want downloaded to your client, including the stubs for your remote object
implementation classes.
If you start the rmiregistry, and it can find your stub classes in its CLASSPATH, it will ignore the
server's java.rmi.server.codebase property, and as a result, your client(s) will not be able to
download the stub code for your remote object. For an explanation of how code downloading works in
RMI, please take a look at the tutorial on Dynamic code downloading using RMI.
To start the registry on the server, execute the rmiregistry command. This command produces no
output and is typically run in the background. For more on the rmiregistry, you can refer to the
Solaris rmiregistry manual page or the Windows rmiregistry manual page.
rmiregistry &
start rmiregistry
By default, the registry runs on port 1099. To start the registry on a different port, specify the port
number from the command line. For example, to start the registry on port 2001 on a Microsoft
Windows NT system:
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 9/11
1/9/2019 Getting Started Using RMI
start rmiregistry 2001
If the registry is running on a port other than 1099, you'll need to specify the port number in the name
handed to the URL-based methods of the java.rmi.Naming class when making calls to the registry.
For example, if the registry is running on port 2001 in this example, the call required to bind the name
"HelloServer" to the remote object reference would be:
Naming.rebind("//myhost:2001/HelloServer", obj);
You must stop and restart the registry any time you modify a remote interface or use
modified/additional remote interfaces in a remote object implementation. Otherwise, the type of the
object reference bound in the registry will not match the modified class.
For explanations of each of the java.rmi.server properties, click here. To see all the available
java.rmi.activation properties, click here. For an explanation of java options, you can refer to the
Solaris java manual page or the Windows java manual page. If you have problems running the
example code, please take a look at the RMI and Serialization FAQ.
Note: A stub class is dynamically downloaded to a client's virtual machine only when the class is not
already available locally and the java.rmi.server.codebase property has been set properly to
specify where the class files are located on the server.
There are four things that need to go on the same command line: the "java" command, followed by
two property name=value pairs (for the codebase property, note that there are no spaces from the "-D"
all the way though the last "/") and then the fully-qualified package name of the server program. There
should be a space just after the word "java", between the two properties, and just before the word
"examples" (which is very hard to see when you view this as text, in a browser, or on paper). The
following command shows how to start the HelloImpl server, specifying the
java.rmi.server.codebase and java.security.policy properties:
java -Djava.rmi.server.codebase=http://myhost/~myusrname/myclasses/ -
Djava.security.policy=$HOME/mysrc/policy examples.hello.HelloImpl
In order to run this code on your system, you'll need to change the location of the policy file to be the
location of the directory on your system, where you've installed the example source code.
Note: In this example, for simplicity, we will use a policy file that gives global permission to anyone
from anywhere. Do not use this policy file in a production environment. For more information on how
to properly open up permissions using a java.security.policy file, please refer to to the following
documents:
The codebase property will be resolved to a URL, so it must have the form of
"http://aHost/somesource/" or "file:/myDirectory/location/" or, due to the requirements of
some operating systems, "file:///myDirectory/location/" (three slashes after the "file:").
Please note that each of the URL strings above has a trailing "/". The trailing slash is a requirement for
the URL set by the java.rmi.server.codebase property, so the implementation can resolve (find)
your class definition(s) properly.
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 10/11
1/9/2019 Getting Started Using RMI
If you forget the trailing slash on the codebase property, or if the class files can't be located at the
source (they aren't really being made available for download) or if you misspell the property name,
you'll get thrown a java.lang.ClassNotFoundException. This exception will be thrown when you try
to bind your remote object to the rmiregistry, or when the first client attempts to access that object's
stub. If the latter case occurs, you have another problem as well because the rmiregistry was finding
the stubs in its CLASSPATH.
After running the appletviewer, you will see output similar to the following on your display:
*As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.
Copyright © 2003 Sun Microsystems, Inc. All Rights Reserved.
Please send comments to: rmi-comments@java.sun.com
https://docs.huihoo.com/java/javase/1.4.2/guide/rmi/getstart.doc.html 11/11