Logo of the Java RMI Plug-in for Eclipse

RMI Plug-in for Eclipse
version 2.0

Java RMI - The Print Server Tutorial



In this "Print Server" tutorial you will create a simple Java RMI application and understand how the RMI Plug-in for Eclipse makes it simpler to develop and evolve RMI applications.

The Print Server System

The print server is an application that makes it possible for a client to submit a print job to one of the 3 (virtually) attached printers. Each print job is assigned a numeric id and the client can later query the job status using that id.

The client application receives the server's name as a command line argument. It connects to the RMI registry on the server, picks a random printer out of the 3 available printers and submits a print job (which is a simple text string). After submitting the job, the print client queries the server for the print job's status until the job completes and prints the output to the console.

Try the system

Before going into further detail, let's get some feeling of a working Java RMI system. It is assumed you have successfully downloaded and installed the RMI Plug-in for Eclipse.

  1. Select "File->New->Project..." or "File->New->Other..." (Ctrl+N).
  2. Expand the "Java" category and locate the "RMI" subcategory.
    Inside the RMI category locate the "RMI Project tutorials" item
    (in Eclipse 3.2 you can simply type "RMI" in the filter field). Select it and press "Next".

(2. click to enlarge)
  1. On the next page, select the "Print Server" projects set. After pressing "Next" either accept the default project names or change them as you wish.
  2. After you finish the wizard, three projects will be created for you including all the files and settings that you need to make it work. You can see how your workbench will look like by clicking the screenshot on the right.

(3. click to enlarge)

(4. click to enlarge)
  1. You've probably noticed that a "cheat sheet" has been opened as well. The cheat sheet is simply another general guide for working with RMI project examples. You can either use it to perform the next steps or close it and continue using this guide.
  2. Now it's probably a good time to open the source files and take a look at the implementation details.
  1. The RMI registry is a necessary part of every RMI system and it must be running in order for the print server example to work. You can start the RMI Registry by using the RMI Plug-in's toolbar button.
  2. The RMI Registry Inspector is a nifty tool that shows the contents of the RMI registry. Let's open now the Registry Inspector (using the same toolbar menu from the previous step) and make sure the registry is empty indeed. After running the server, you'll see some objects in the registry.
(7. click to enlarge)
(8. click to enlarge)
  1. Now it's time to run the print server application. Open the "Run" dialog using the "Run->Run..." menu. Choose the "Print Server" configuration and run it.
    The console window should say "The print server is ready". The RMI Registry Inspector will now report (int its title) that there are three objects in the local registry. If you switch to the RMI Registry Inspector view, you will see the three objects, called "printer1", "printer2", "printer3".

(9. click to enlarge)
  1. After the print server has been successfully started, it's time to start the print client (using similar steps). The screenshot shows what you should see in the console window (the actual job and printer status may vary, which is ok, since the server implementation uses random values)..
(10. click to enlarge)

Understanding the Print Server example

The examples wizard has done much of the dirty work that one has to do in order build a working Java RMI system. Yet, it is important to understand what has been done in order to be able to build and evolve such system. In the next sections all components of the Print Server system will be presented. This is not an RMI tutorial, and it won't go into detailed explanation of why the system is built the way it is built, but rather discuss the technical details of how it's done.

The common interfaces

The RemotePrinter interface which extends java.rmi.Remote defines 3 remote methods for submitting a new job, status query for a submitted job and for the remote printer itself. Notice that each method must declare throwing a RemoteException.

The RemotePrinter interface could be part of the print server project and in order to use the RemotePrinter interface, the client could have the server project on its build path. However that would cause some problems during deployment (and when trying to run the example outside eclipse). Instead, the RemotePrinter interface is created in a separate project and both the client and the server projects have the common interfaces project on their build path.

The server code

The server project contains the implementation of the RemotePrinter interface. The actual implementation of these 3 methods defined by the interface is not very interesting for the purpose of this tutorial, and won't be presented here. Other elements of the RemotePrinterImpl class are more interesting and important.

In this example, the implementation class extends the UnicastRemoteObject class. The implementation of UnicastRemoteObject's constructors takes care of making the object visible in the RMI system. This is also the reason why we must declare the constructor throwing a RemoteException (try deleting it, or the whole constructor and see what happens).

The main() method of the RemotePrinterImpl class does the job of connecting to the local registry, creating three printer instances and registering them in the local RMI registry. The registration is performed by explicitly accessing the registry, although Naming.rebind() could work as well. If everything was successful, the print server writes "The printer server is ready" to the console.

The client code

The print client consists of a single java class - the PrintClient class. Its main() method expects to receive the server name as a command line argument ("localhost" was used when you ran the client earlier in this tutorial). The client then tries to connect to the registry on the server machine and picks a random remote printer. Note that in our example the RMI registry and the print server run as separate processes (which can run on different machines as well) and RMI takes care of all the hard work. Holding a reference to the remote printer, the print client submits a new print job (simple text string) and receives its job id. Then it queries the job and printer status until the job is complete.

Running the server

Since the print server is a very simple RMI application, not much configuration is needed in order to run it. In fact, all we need is to create the RMI stubs and to set up is the codebase. Stub classes have important role in the RMI system - they implement a remote interface (like RemotePrinter) and when loaded by the client, delegate all remote method calls to the server. The RMI Plug-in for Eclipse takes care of generating the stubs for you (the examples wizard enables stubs generation for the print server project). Note that starting with Java 5.0 you don't have to generate the stubs - Java can dynamically create them for you, but creating them explicitly is still useful.

The codebase property

The codebase property is a VM property (supplied using the -D switch) that is responsible for remote class-loading configuration. For a server project it declares where the remote interfaces and stub classes are located. In our example, the client project does not have any access to the server project (it's not on client's classpath). If so, how can the client load the RemotePrinterImpl's stub? The RMI solution is simple - the remote object is annotated with a codebase property that acts like an "extra" classpath. Whoever uses the remote object consults the additional codebase entry when resolving classes. Additionally, the rmiregistry does not have anything on its classpath at all (it's better that way), and therefore it can only rely on the codebase supplied by the registered object.

But where does the codebase annotation come from? Since the codebase is a property of the remote object, it is exported by remote object's JVM (Print Server's JVM in our case). How does the server VM get the codebase? Simple - it uses the -Djava.rmi.server.codebase VM property that was specified when the server JVM was launched. (Note that all objects created by the same JVM will have the same codebase annotation.)

In the print server example, the wizard has defined a codebase property in the server's launch configuration (see screenshot). Using the codebase editor you can configure the codebase property to reference any location in your workspace, file system or on the web. More information about possible codebase problems can be found here.


(click to enlarge)

(click to enlarge)

Running the client

The print server is a very simple Java RMI system, but it demonstrates many aspects of a real complex RMI system. One such aspect is how does a client interact with a remote server without being dependent on the server implementation's classes. Indeed, the print client does not depend on the server project and it interacts with the server through the RemotePrinter interface, which is defined in the "common" project. Yet the print client must access the RemotePrinterImpl's stub (not with JDK 1.5, see note later) and it must load it from the codebase location (see previous section for a codebase discussion).

In order to allow remote class loading, the client implementation must install a security manager. Therefore the following line must be present in the client's code:

   System.setSecurityManager(new RMISecurityManager());

Since the security manager requires a security policy, the wizard has created an all-permissive security policy file and added the -Djava.security.policy VM property to the Print Client launch.

Note about Java 5.0/JDK 1.5: While since JDK 1.5 the RMI implementation can auto-generate the stub class on the client side, the client may still need access to server's codebase. For example if the submitJob() method throws any subclass of the RemoteException (for example the PrinterException exception) the client must be able to load the exception's class. Since the client knows nothing about a PrinterException (it only knows about the RemoteException declared in the RemotePrinter interface) it must load it from the codebase.


© 2002-18 Genady Beryozkin, rmi-info@genady.net. Read our Privacy policy. Hosted on RimuHosting. Visit Javalobby.