The java.rmi.server
package is the most complex of all the RMI packages; it contains the
scaffolding for building remote objects and thus is used by objects
whose methods will be invoked by clients. The package defines 6
exceptions, 9 interfaces, and 10 classes. Fortunately, you need to be
familiar with only a few of these to write remote objects. The
important classes are the RemoteObject
class,
which is the basis for all remote objects; the
RemoteServer
class, which extends
RemoteObject
; and the
UnicastRemoteObject
class, which extends
Remote Server
. Any remote objects you write will
likely either extend or use UnicastRemoteObject
.
Clients that call remote methods but are not themselves remote
objects don’t use these classes, and therefore don’t need
to import java.rmi.server
.
Technically, a remote object is not an instance of the
RemoteObject
class but an instance of any class that
implements a Remote
interface. In practice, most
remote objects will be instances of a subclass of
java.rmi.server.RemoteObject
:
public abstract class RemoteObject extends Object implements Remote, Serializable
You can think of this class as a special version of
java.lang.Object
for remote objects. It provides
toString( )
, hashCode( )
,
clone( )
, and equals( )
methods
that make sense for remote objects. If you create a remote object
that does not extend RemoteObject
, you need to
override these methods yourself.
The equals( )
method compares the remote object
references of two RemoteObject
s and returns true
if they point to the same remote object. As with the equals( )
method in the Object
class, you may
want to override this method to provide a more meaningful definition
of equality.
The toString( )
method returns a
String
that describes the remote object. Most of
the time, toString( )
returns the hostname and
port from which the remote object came as well as a reference number
for the object. You can override this method in your own subclasses
to provide more meaningful string representations.
The hashCode( )
method maps a presumably unique
int
to each unique object; this integer may be
used as a key in a Hashtable
. It returns the same
value for all remote references that refer to the same remote object.
Thus, if a client has several remote references to the same object on
the server, or multiple clients have references to that object, they
should all have the same hash code.
Starting in Java 1.2, there’s one other instance method in this
class, getRef( )
:
public RemoteRef getRef( ) // Java 1.2
This returns a remote reference to the class:
public abstract interface RemoteRef extends Externalizable
Java 1.2 also adds one static method, RemoteObject.toStub( )
:
public static Remote toStub(Remote ro) // Java 1.2 throws NoSuchObjectException
RemoteObject.toStub( )
converts a given remote object
into the equivalent stub object for use in the client virtual
machine. This can help you dynamically generate stubs from within
your server without using rmic
.
The RemoteServer
class extends
RemoteObject
; it is an abstract superclass for
server implementations such as
UnicastRemoteObject
. It provides a few simple utility methods
needed by most server objects:
public abstract class RemoteServer extends RemoteObject
In Java 1.1, UnicastRemoteObject
is the only
subclass of RemoteServer
included in the core
library. Java 1.2 adds the
java.rmi.activation.Activatable
and
java.rmi.activation.ActivationGroup
classes. You
can add others (for example, a UDP or multicast remote server) by
writing your own subclass of RemoteServer
.
There are two constructors for this class:
protected RemoteServer( ) protected RemoteServer(RemoteRef r)
However, you won’t instantiate this class yourself. Instead,
you will instantiate a subclass like
UnicastRemoteObject
. That class’s
constructor will call one of these protected constructors from the
first line of its constructor.
The
RemoteServer
class has one method to locate the
client with which you’re communicating:
public static String getClientHost( ) throws ServerNotActiveException
RemoteServer.getClientHost( )
returns a
String
that contains the hostname of the client
that invoked the currently running method. This method throws a
ServerNotActiveException
if the current thread is
not running a remote method.
For
debugging purposes, it is sometimes useful to see the calls that are
being made to your remote object and the object’s responses.
You can get a log for your RemoteServer
by passing
an OutputStream
object to the setLog( )
method:
public static void setLog(OutputStream out)
Passing null
turns off logging. For example, to
see all the calls on System.err
(which sends the
log to the Java console), you would write:
myRemoteServer.setLog(System.err);
For example, here’s some log output I collected while debugging the Fibonacci programs in this chapter:
Sat Apr 29 12:20:36 EDT 2000:RMI:TCP Accept-1:[titan.oit.unc.edu: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)] Fibonacci Server ready. Sat Apr 29 12:21:27 EDT 2000:RMI:TCP Accept-2:[macfaq.dialup.cloud9.net: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)] Sat Apr 29 12:22:36 EDT 2000:RMI:TCP Accept-3:[macfaq.dialup.cloud9.net: sun.rmi. transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)] Sat Apr 29 12:22:39 EDT 2000:RMI:TCP Accept-3:[macfaq.dialup.cloud9.net: FibonacciImpl[0]: java.math.BigInteger getFibonacci(java.math.BigInteger)] Sat Apr 29 12:22:39 EDT 2000:RMI:TCP Accept-3:[macfaq.dialup.cloud9.net: FibonacciImpl[0]: java.math.BigInteger getFibonacci(java.math.BigInteger)]
If you want to add extra information to the log, in addition to
what’s provided by the RemoteServer
class,
you can retrieve the log’s PrintStream
with
the getLog( )
method:
public static PrintStream getLog( )
Once you have the print stream, you can write on it to add your own comments to the log. For example:
PrintStream p = RemoteServer.getLog( ); p.println("There were " + n + " total calls to the remote object.");
The UnicastRemoteObject
class is a concrete subclass of RemoteServer
. To
create a remote object, you can extend
UnicastRemoteObject
in your own subclass and
declare that your subclass implements some subclass of the
java.rmi.Remote
interface. The methods of the
interface provide functionality specific to the class, while the
methods of UnicastRemoteObject
handle general
remote object tasks like marshaling and unmarshaling arguments and
return values. All of this happens behind the scenes. As an
application programmer, you don’t need to worry about it.
A UnicastRemoteObject
runs on a single host, uses
TCP sockets to communicate, and has remote references that do not
remain valid across server restarts. While this is a good
general-purpose framework for remote objects, it is worth noting that
you can implement other kinds of remote objects. For example, you may
want a remote object that uses UDP, or one that remains valid if the
server is restarted, or even one that distributes the load across
multiple servers. To create remote objects with these properties, you
would extend RemoteServer
directly and implement
the abstract methods of that class. However, if you don’t need
anything so esoteric, you will find it much easier to subclass
UnicastRemoteObject
.
The
UnicastRemoteObject
class has three protected
constructors:
protected UnicastRemoteObject( ) throws RemoteException protected UnicastRemoteObject(int port) // Java 1.2 throws RemoteException protected UnicastRemoteObject(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException // Java 1.2
The noargs constructor creates a
UnicastRemoteObject
that listens on an anonymous
port chosen at runtime.[31] Java 1.2 adds two more
constructors that listen on the specified port. The third constructor
also allows you to specify the socket factories used by this
UnicastRemoteObject
. When you write a subclass of
UnicastRemoteObject
, you call one of these
constructors, either explicitly or implicitly, in the first line of
each constructor of your subclass. All three constructors can throw a
RemoteException
if the remote object cannot be
created.
The UnicastRemoteObject
class has several public
methods:
public Object clone( ) throws CloneNotSupportedException public static RemoteStub exportObject(Remote r) throws RemoteException public static Remote exportObject(Remote r, int port) throws RemoteException // Java 1.2 public static Remote exportObject(Remote r, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException // Java 1.2 public static boolean unexportObject(Remote r, boolean force) throws NoSuchObjectException // Java 1.2
The clone( )
method simply creates a
clone of the remote object. You call the
UnicastRemoteObject.exportObject( )
to use the
infrastructure that Unicast RemoteObject
provides
for an object that can’t subclass Unicast RemoteObject
Similarly, you pass an object
UnicastRemoteObject.unexportObject( )
to stop a
particular remote object from listening for invocations.
The java.rmi.server
package defines six new exceptions. The exceptions and their meanings
are listed in Table 18.3. All except
java.rmi.server.ServerNotActiveException
extend,
directly or indirectly, java.rmi.RemoteException
.
All are checked exceptions that must be caught or declared in a
throws
clause.
Table 18-3. java.rmi.server Exceptions
Exception |
Meaning |
---|---|
|
You’re trying to export a remote object on a port that’s already in use. |
|
An attempt was made to invoke a method in a remote object that wasn’t running. |
|
An attempt to clone a remote object on the server failed. |
|
This subclass of |
|
The server is unable to load the skeleton it needs to respond to a remote method invocation. This can mean several things: the skeleton class file may not be anywhere in the codebase; the skeleton is in the codebase but has a name conflict with another class; the URL given may be incorrect; or the skeleton may be of the wrong class. This is deprecated starting in Java 1.2 because skeletons are no longer used. |
|
The skeleton and the stub for a class don’t match. This is unusual but may happen if different versions of the source code are used to make the stub and the skeleton. This is deprecated starting in Java 1.2 because skeletons are no longer used. |
This chapter has been a fairly quick look at Remote Method Invocation. For a more detailed treatment, see Java Distributed Computing, by Jim Farley (O’Reilly & Associates, Inc., 1998).
[31] By the way, this is an example of an obscure situation I mentioned in Chapter 10, and Chapter 11. The server is listening on an anonymous port. Normally, this would be next to useless because it would be impossible for clients to locate the server. In this case, clients locate servers by using a registry, which keeps track of what servers are available and what ports they are listening to.
3.140.185.170