RMI (Remote Method Invocation) Communication Example
RMI allows you to set up an object so it runs on a remote host and then
execute operations on that object just as if you were executing methods on
non-RMI-based objects. For example, you could set up an object
representing a time log with operations to add and retrieve data. The
object would be stored in a file so you don't lose information every time
the server is restarted.
You must create several pieces to use RMI in an application:
- An interface for the service. This simply defines the methods that
will be available to clients.
- An implementation of the service. This piece actually does the work
specified in the interface.
- A client for the service. This could be an Applet or standalone Java
program.
Once the application has been set up, you use it by doing the following:
- Compile the implementation.
- Run rmiregistry 10000
(using the same port number as
in CounterServiceImpl.java)
- Run the server implementation.
- Run the client(s).
Note that you must run rmiregistry before you can start your
server, and the server must be running before you can start any clients.
For example, consider the following Java files which implement a simple
counter:
- CounterService.java: the
interface for the service with methods to increment, decrement, and get the
value of the counter. Notes:
- All data being passed to and from such objects must either be primitive
or serializable.
- The service extends java.rmi.Remote.
- All methods throw RemoteException.
- CounterServiceImpl.java:
an implementation of the counter service. This code will be run on the
server host. Notes:
- By convention, this class's name is typically formed by taking the
interface class name and appending "Impl".
- The class extends UnicastRemoteObject and implements the
service. UnicastRemoteObject gives point-to-point communication
(as opposed to such things as broadcast-based communication).
- The constructor (as well as the methods that are in the interface) must
throw RemoteException.
- This class contains a main that sets up the service. It
creates an instance of the service implementation, and uses
Naming.rebind to register the service so clients can connect to
it. You will want to use a distinct name for services you create; I
suggest the pattern login-service where
login is your login name and service is
your name for the service. (Warning: don't use
Naming.bind instead of Naming.rebind; the latter allows
you to redefine the service during debugging and the former doesn't.) You
will also need to pick a port number.
- The exception handing code in main attempts to recover from
network errors. In your application, you would want to generate more
descriptive error messages.
- CounterClient.java: a JFrame
which accesses the counter. Notes:
- The "implements ActionListener" code is just so I can handle
button events; it doesn't have anything to do with the RMI code itself.
- The critical part related to RMI is in the CounterFrame
constructor where I access the service remotely. Again, you'd put in your
own service name and try to write better error handling routines.
- incrementField illustrates accessing the remote service,
complete with (simplified) error handling.
- incr.java: a simple command-line
program which connects to the counter server, adds one to the counter, and
prints the result. I found this sort of code very helpful when
getting RMI to work because then I was sure problems were related to RMI
and not to applets. You might also find such programs useful for
test plans.
To run this application on server Xyz, do the following:
- Copy the files to your home directory.
- Edit CounterServiceImpl.java to update the service name,
port id (see above for suggested formats), and service host.
- Compile all code with
javac *.java
- Type
rmiregistry port
to start rmiregistry (where port is the number used in
the second step).
- Log in to the host and type
java CounterServiceImpl
Note that neither rmiregistry nor CounterServiceImpl
exits until you type Control-C.
- Do one of the following:
- start another ssh session and compile and execute incr.java, or
- download the .class files and run CounterFrame.class, or
- download the .class files and compile and execute
incr.java.
For More Information
The above information was gleaned from
- Advanced Techniques for Java Developers, Revised Edition, by
Daniel J. Berg and J. Steven Fritzinger (Wiley, 1999); and
- Advanced Java 2 Platform: How to Program by H. M. Deitel,
P. J. Deitel, and S. E. Santry (Prentice Hall, 2002)
Both books contain further information such as how to make the server "call
back" to the client to inform the client of changes to the data stored on
the server.
More information is available at Sun's RMI documentation
site. Please let me know of other sites you find that are useful.
Security
Warning: be careful about running rmiregistry;
there could be any a number of ways it could be used by another user to
gain access to your files. It would generally be better to
quit rmiregistry when you're not using it to test. Also, you
would definitely want to investigate the security issues before using this
tool in industry!