Remote methods | CodeGuru

Remote methods

Bruce Eckel’s Thinking in Java Contents | Prev | Next Traditional approaches to executing code on other machines across a network have been confusing as well as tedious and error-prone to implement. The nicest way to think about this problem is that some object happens to live on another machine, and you can send a […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
8 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Traditional


approaches to executing code on other machines across a network have been


confusing as well as tedious and error-prone to implement. The nicest way to


think about this problem is that some object happens to live on another


machine, and you can send a message to that object and get a result as if the


object lived on your local machine. This simplification is exactly what Java 1.1


Remote
Method Invocation

(RMI) allows you to do. This section walks you through the steps necessary to
create your own RMI objects.

Remote
interfaces

RMI


makes heavy use of interfaces. When you want to create a remote object, you


mask the underlying implementation by passing around an interface. Thus, when


the client gets a handle to a remote object, what they really get is an


interface handle, which


happens

to connect to some local stub code that talks across the network. But you


don’t think about this, you just send messages via your interface handle.

When


you create a

remote
interface, you must follow these guidelines:
  1. The
    remote interface must be
    public
    (it cannot have “package access,” that is, it cannot be
    “friendly”). Otherwise, a client will get an error when attempting
    to load a remote object that implements the remote interface.
  2. The
    remote interface must extend the interface java.rmi.Remote.
  3. Each
    method in the remote interface must declare java.rmi.RemoteException
    in its
    throws
    clause in addition to any application-specific exceptions.
  4. A
    remote object passed as an argument or return value (either directly or
    embedded within a local object) must be declared as the remote interface, not
    the implementation class.

Here’s


a simple remote interface that represents an accurate time service:

//: PerfectTimeI.java
// The PerfectTime remote interface
package c15.ptime;
import java.rmi.*;
 
interface PerfectTimeI extends Remote {
  long getPerfectTime() throws RemoteException;
} ///:~ 

It


looks like any other interface except that it extends


Remote

and all of its methods throw


RemoteException

.


Remember that an


interface

and all of its methods are automatically


public

.

Implementing
the remote interface

The


server must contain a class that extends

UnicastRemoteObject
and implements the remote interface. This class can also have additional
methods, but only the methods in the remote interface will be available to the
client, of course, since the client will get only a handle to the interface,
not the class that implements it.

You


must explicitly define the constructor for the remote object even if


you’re only defining a default constructor that calls the base-class


constructor. You must write it out since it must throw


RemoteException

.

Here’s


the implementation of the remote interface


PerfectTimeI

:

//: PerfectTime.java
// The implementation of the PerfectTime 
// remote object
package c15.ptime;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.net.*;
 
public class PerfectTime
    extends UnicastRemoteObject
    implements PerfectTimeI {
  // Implementation of the interface:
  public long getPerfectTime()
      throws RemoteException {
    return System.currentTimeMillis();
  }
  // Must implement constructor to throw
  // RemoteException:
  public PerfectTime() throws RemoteException {
    // super(); // Called automatically
  }
  // Registration for RMI serving:
  public static void main(String[] args) {
    System.setSecurityManager(
      new RMISecurityManager());
    try {
      PerfectTime pt = new PerfectTime();
      Naming.bind(
        "//colossus:2005/PerfectTime", pt);
      System.out.println("Ready to do time");
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
} ///:~ 

Here,


main( )

handles all the details of setting up the server. When you’re serving RMI


objects, at some point in your program you must:

  1. Create
    and install a security manager that supports RMI. The only one available for
    RMI as part of the Java distribution is RMISecurityManager.
  2. Create
    one or more instances of a remote object. Here, you can see the creation of the
    PerfectTime
    object.
  3. Register
    at least one of the remote objects with the RMI remote
    object registry for bootstrapping purposes. One remote object can have methods
    that produce handles to other remote objects. This allows you to set it up so
    the client must go to the registry only once, to get the first remote object.


Setting
up the registry

Here,


you see a call to the


static

method

Naming.bind( ).
However, this call requires that the registry be running as a separate process
on the computer. The name of the registry server is
rmiregistry,
and under 32-bit Windows you say:
start
rmiregistry

to


start it in the background. On Unix, it is:

rmiregistry
&

Like


many network programs, the


rmiregistry

is located at the IP address of whatever machine started it up, but it must


also be listening at a port. If you invoke the


rmiregistry

as above, with no argument, the registry’s port will default to 1099. If


you want it to be at some other port, you add an argument on the command line


to specify the port. For this example, the port will be located at 2005, so the


rmiregistry

should be started like this under 32-bit Windows:

start
rmiregistry 2005

or


for Unix:

rmiregistry
2005 &

The


information about the port must also be given to the


bind( )

command, as well as the IP address of the machine where the registry is


located. But this brings up what can be a frustrating problem if you’re


expecting to test RMI programs locally the way the network programs have been


tested so far in this chapter. In the JDK 1.1.1 release, there are a couple of


problems:


[69]
  1. localhost
    does
    not work with RMI. Thus, to experiment with RMI on a single machine, you must
    provide the name of the machine. To find out the name of your machine under
    32-bit Windows, go to the control panel and select “Network.”
    Select the “Identification” tab, and you’ll see your computer
    name. In my case, I called my computer “Colossus” (for all the hard
    disks I’ve had to put on to hold all the different development systems).
    It appears that capitalization is ignored.
  2. RMI
    will not work unless your computer has an active TCP/IP
    connection, even if all your components are just talking to each other on the
    local machine. This means that you must connect to your Internet service
    provider before trying to run the program or you’ll get some obscure
    exception messages.

Will


all this in mind, the


bind( )

command becomes:

Naming.bind("//colossus:2005/PerfectTime",
pt);

If


you are using the default port 1099, you don’t need to specify a port, so


you could say:

Naming.bind("//colossus/PerfectTime",
pt);

In


a future release of the JDK (after 1.1) when the


localhost

bug is fixed, you will be able to perform local testing by leaving off the IP


address and using only the identifier:

Naming.bind("PerfectTime",
pt);

The


name for the service is arbitrary; it happens to be PerfectTime here, just like


the name of the class, but you could call it anything you want. The important


thing is that it’s a unique name in the registry that the client knows to


look for to procure the remote object. If the name is already in the registry,


you’ll get an

AlreadyBoundException.
To prevent this, you can always use
rebind( )
instead of
bind( ),
since
rebind( )
either adds a new entry or replaces the one that’s already there.

Even


though


main( )

exits, your object has been created and registered so it’s kept alive by


the registry, waiting for a client to come along and request it. As long as the


rmiregistry

is running and you don’t call


Naming.unbind( )
on
your name, the object will be there. For this reason, when you’re
developing your code you need to shut down the
rmiregistry
and restart it when you compile a new version of your remote object.

You


aren’t forced to start up


rmiregistry

as an external process. If you know that your application is the only one


that’s going to use the registry, you can start it up inside your program


with the line:

LocateRegistry.createRegistry(2005);

Like


before, 2005 is the port number we happen to be using in this example. This is


the equivalent of running


rmiregistry
2005

from a command line, but it can often be more convenient when you’re


developing RMI code since it eliminates the extra steps of starting and


stopping the registry. Once you’ve executed this code, you can


bind( )

using


Naming

as before.


Advertisement

Creating
stubs and skeletons

If


you compile and run


PerfectTime.java

,


it won’t work even if you have the


rmiregistry

running correctly. That’s because the framework for RMI isn’t all


there yet. You must first create the

stubs
and
skeletons
that provide the network connection operations and allow you to pretend that
the remote object is just another local object on your machine.

What’s


going on behind the scenes is complex. Any objects that you pass into or return


from a remote object must


implement
Serializable

(if you want to pass remote references instead of the entire objects, the


object arguments can


implement
Remote

),


so you can imagine that the stubs and skeletons are automatically performing


serialization and deserialization as they “marshal” all of the


arguments across the network and return the result. Fortunately, you


don’t have to know any of this, but you


do

have to create the stubs and skeletons. This is a simple process: you invoke the

rmic
tool on your compiled code, and it creates the necessary files. So the only
requirement is that another step be added to your compilation process.

The


rmic

tool is particular about packages and

classpaths,
however.
PerfectTime.java
is in the package
c15.Ptime,
and even if you invoke
rmic
in the same directory in which
PerfectTime.class
is located,
rmic
won’t find the file, since it searches the classpath. So you must specify
the location off the class path, like so:
rmic
c15.PTime.PerfectTime

You


don’t have to be in the directory containing


PerfectTime.class

when you execute this command, but the results will be placed in the current


directory.

When


rmic

runs successfully, you’ll have two new classes in the directory:

PerfectTime_Stub.class
PerfectTime_Skel.class

corresponding


to the stub and skeleton. Now you’re ready to get the server and client


to talk to each other.


Using
the remote object

The


whole point of RMI is to make the use of remote objects simple. The only extra


thing that you must do in your client program is to look up and fetch the


remote interface from the server. From then on, it’s just regular Java


programming: sending messages to objects. Here’s the program that uses


PerfectTime

:

//: DisplayPerfectTime.java
// Uses remote object PerfectTime
package c15.ptime;
import java.rmi.*;
import java.rmi.registry.*;
 
public class DisplayPerfectTime {
  public static void main(String[] args) {
    System.setSecurityManager(
      new RMISecurityManager());
    try {
      PerfectTimeI t =
        (PerfectTimeI)Naming.lookup(
          "//colossus:2005/PerfectTime");
      for(int i = 0; i < 10; i++)
        System.out.println("Perfect time = " +
          t.getPerfectTime());
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
} ///:~ 

The


ID string is the same as the one used to register the object with


Naming

,


and the first part represents the URL and port number. Since you’re using


a URL, you can also specify a machine on the Internet.

What


comes back from


Naming.lookup( )

must be cast to the remote interface,


not

to the class. If you use the class instead, you’ll get an exception.

You


can see in the method call

t.getPerfectTime( )

that


once you have a handle to the remote object, programming with it is


indistinguishable from programming with a local object (with one difference:


remote methods throw

RemoteException).

Advertisement

Alternatives
to RMI

RMI


is just one way to create objects that can be distributed across a network. It


has the advantage of being a “pure Java” solution, but if you have


a lot of code written in some other language, it might not meet your needs. The


two most compelling alternatives are Microsoft’s

DCOM
(which, according to Microsoft’s plan, will eventually be hosted on
platforms other than Windows) and
CORBA,
which is supported in Java 1.1

and was designed from the start to be cross-platform. You can get an
introduction to distributed objects in Java (albeit with a clear bias towards
CORBA) in
Client/Server
Programming with Java and CORBA

by Orfali & Harkey (John Wiley & Sons, 1997). A more serious treatment
of CORBA is given by
Java
Programming with CORBA

by

Andreas
Vogel

and
Keith Duddy (John Wiley & Sons, 1997).


[69]

Many brain cells died in agony to discover this information.

Contents

|

Prev

|

Next
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.