18.1 What Is Remote Method Invocation?
RMI
lets Java objects on different hosts communicate with each other in a
way that's similar to how objects running in the
same virtual machine communicate with each other: by calling methods
in objects. A remote object lives on a server. Each remote object
implements a remote interface that specifies which of its methods can
be invoked by clients. Clients invoke the methods of the remote
object almost exactly as they invoke local methods. For example, an
object running on a local client can pass a database query as a
String argument to a method in a database object
running on a remote server to ask it to sum up a series of records.
The server can return the result to the client as a
double. This is more efficient than downloading
all the records and summing them up locally. Java-compatible web
servers can implement remote methods that allow clients to ask for a
complete index of the public files on the site. This could
dramatically reduce the time a server spends filling requests from
web spiders such as Google. Indeed, Excite already uses a
non-Java-based version of this idea.From the programmer's perspective, remote objects
and methods work pretty much like the local objects and methods
you're accustomed to. All the implementation details
are hidden. You just import one package, look up the remote object in
a registry (which takes one line of code), and make sure that you
catch
RemoteException
when you call the object's methods. From that point
on, you can use the remote object almost as freely and easily as you
use an object running on your own system. The abstraction is not
perfect. Remote method invocation is much slower and less reliable
than regular local method invocation. Things can and do go wrong with
remote method invocation that do not affect local method invocations.
For instance, a local method invocation is not subject to a Verizon
technician disconnecting your DSL line while working on the phone
line next door. Network failures of this type are represented as
RemoteExceptions. However, RMI tries to hide the
difference between local and remote method invocation to the maximum
extent possible.More formally, a remote
object is an object with methods that may be
invoked from a different Java virtual machine than the one in which
the object itself lives, generally one running on a different
computer. Each remote object implements one or more remote
interfaces that declare which methods of the remote object
can be invoked by the foreign system. RMI is the facility by which a
Java program running on one machine, say
java.oreilly.com, can invoke a method in an
object on a completely different machine, say
www.ibiblio.org.For example, suppose weather.centralpark.org is
an Internet-connected PC at the Central Park weather station that
monitors the temperature, humidity, pressure, wind speed and
direction, and similar information through connections to various
instruments, and it needs to make this data available to remote
users. A Java program running on that PC can offer an interface like
Example 18-1 that provides the current values of the
weather data.
Example 18-1. The weather interface
import java.rmi.*;Normally, this interface is limited to other programs running on that
import java.util.Date;
public interface Weather extends Remote {
public double getTemperature( ) throws RemoteException;
public double getHumidity( ) throws RemoteException;
public double getPressure( ) throws RemoteException;
public double getWindSpeed( ) throws RemoteException;
public double getWindDirection( ) throws RemoteException;
public double getLatitude( ) throws RemoteException;
public double getLongitude( ) throws RemoteException;
public Date getTime( ) throws RemoteException;
}
same PCindeed, in the same virtual machine. However, remote
method invocations allow other virtual machines running on other
computers in other parts of the world to invoke these methods to
retrieve the weather data. For instance, a Java program running on my
workstation at stallion.elharo.com could look up the current
weather object in the RMI registry at weather.centralpark.org. The registry would
send it a reference to the object running in weather.centralpark.org's
virtual machine. My program could then use this reference to invoke
the getTemperature( ) method. The
getTemperature( ) method would execute on the
server in Central Park, not on my local machine. However, it would
return the double value back to my local program running in Brooklyn.
This is simpler than designing and implementing a new socket-based
protocol for communication between the weather station and its
clients. The details of making the connections between the hosts and
transferring the data are hidden in the RMI classes.So far we've imagined a public service
that's accessible to all. However, clearly there are
some methods you don't want just anyone invoking.
More RMI applications than not will have a strictly limited set of
permitted users. RMI itself does not provide any means of limiting
who's allowed to access RMI servers. These
capabilities can be added to RMI programs through the Java
Authentication and Authorization Service (JAAS). JAAS is an abstract
interface that can be configured with different service providers to
support a range of different authentication schemes and different
stores for the authentication data.
18.1.1 Object Serialization
When an object is passed to or
returned from a Java method, what's really
transferred is a reference to the object. In most current
implementations of Java, references are handles (doubly indirected
pointers) to the location of the object in memory. Passing objects
between two machines thus raises some problems. The remote machine
can't read what's in the memory of
the local machine. A reference that's valid on one
machine isn't meaningful on the other.There are two ways around this problem. The first way is to convert
the object to a sequence of bytes and send these bytes to the remote
machine. The remote machine receives the bytes and reconstructs them
into a copy of the object. However, changes to this copy are not
automatically reflected in the original object. This is like
pass-by-value.The second way around this problem is to pass a special remote
reference to the object. When the remote machine invokes a method on
this reference, that invocation travels back across the Internet to
the local machine that originally created the object. Changes made on
either machine are reflected on both ends of the connection because
they share the same object. This is like pass-by-reference.Converting an object into a sequence of bytes is more difficult than
it appears at first glance because object fields can be references to
other objects; the objects these fields point to also need to be
copied when the object is copied. And these objects may point to
still other objects that also need to be copied. Object serialization
is a scheme by which objects can be converted into bytes and then
passed around to other machines, which rebuild the original object
from the bytes. These bytes can also be written to disk and read back
from disk at a later time, allowing you to save the state of an
entire program or a single object.For
security reasons, Java places some limitations on which objects can
be serialized. All Java primitive types can be serialized, but
nonremote Java objects can be serialized only if they implement the
java.io.Serializable interface. Basic Java types
that implement Serializable include
String and Component. Container
classes such as Vector are serializable if all the
objects they contain are serializable. Furthermore, subclasses of a
serializable class are also serializable. For example,
java.lang.Integer and
java.lang.Float are serializable because the class
they extend, java.lang.Number, is serializable.
Exceptions, errors, and other throwable objects are always
serializable. Most AWT and Swing components, containers, and events
are serializable. However, event adapters, image filters, and peer
classes are not. Streams, readers and writers, and most other I/O
classes are not serializable. Type wrapper classes are serializable
except for Void. Classes in
java.math are serializable. Classes in
java.lang.reflect are not serializable. The
URL class is serializable. However,
Socket, URLConnection, and most
other classes in java.net are not. If in doubt,
the class library documentation will tell you whether a given class
is serializable.
|
CORBARMI isn't the final word in distributed object systems. Its biggest limitation is that you can call only methods written in Java. What if you already have an application written in some other language, such as C++, and you want to communicate with it? The most general solution for distributed objects is CORBA, the Common Object Request Broker Architecture. CORBA lets objects written in different languages communicate with each other. Java hooks into CORBA through the Java-IDL. This goes beyond the scope of this book; to find out about these topics, see:Java-IDL (http://java.sun.com/products/jdk/idl/)CORBA for Beginners (http://www.omg.org/gettingstarted/corbafaq)The CORBA FAQ list (http://www4.informatik.uni-erlangen.de/~geier/corba-faq/)Client/Server Programming with Java and CORBA by Dan Harkey and Robert Orfali (Wiley) 18.1.2 Under the HoodThe last two sections skimmed over a lot of details. Fortunately, Java hides most of the details from you. However, it never hurts to understand how things really work.The fundamental difference between remote objects and local objects is that remote objects reside in a different virtual machine. Normally, object arguments are passed to methods and object values are returned from methods by referring to something in a particular virtual machine. This is called passing a reference. However, this method doesn't work when the invoking method and the invoked method aren't in the same virtual machine; for example, object 243 in one virtual machine has nothing to do with object 243 in a different virtual machine. In fact, different virtual machines may implement references in completely different and incompatible ways.Therefore, three different mechanisms are used to pass arguments to and return results from remote methods, depending on the type of the data being passed. Primitive types (int, boolean, double, and so on) are passed by value, just as in local Java method invocation. References to remote objects (that is, objects that implement the Remote interface) are passed as remote references that allow the recipient to invoke methods on the remote objects. This is similar to the way local object references are passed to local Java methods. Objects that do not implement the Remote interface are passed by value; that is, complete copies are passed, using object serialization. Objects that do not allow themselves to be serialized cannot be passed to remote methods. Remote objects run on the server but can be called by objects running on the client. Nonremote, serializable objects run on the client system.To make the process as transparent to the programmer as possible, communication between a remote object client and a server is implemented in a series of layers, as shown in Figure 18-1. Figure 18-1. The RMI layer model![]() In reality, the client program talks only to a stub object that stands in for the real object on the remote system. The stub passes that conversation along to the remote reference layer, which talks to the transport layer. The transport layer on the client passes the data across the Internet to the transport layer on the server. The server's transport layer then communicates with the server's remote reference layer, which talks to a piece of server software called the skeleton. The skeleton communicates with the server itself. (Servers written in Java 1.2 and later can omit the skeleton layer.) In the other direction (server-to-client), the flow is simply reversed. Logically, data flows horizontally (client-to-server and back), but the actual flow of data is vertical.This approach may seem overly complex, but remember that most of the time you don't need to think about it, any more than you need to think about how a telephone translates your voice into a series of electrical impulses that get translated back to sound at the other end of the phone call. The goal of RMI is to allow your program to pass arguments to and return values from methods without worrying about how those arguments and return values will move across the network. At worst, you'll simply need to handle one additional kind of exception a remote method might throw.Before you can call a method in a remote object, you need a reference to that object. To get this reference, ask a registry for it by name. The registry is like a mini-DNS for remote objects. A client connects to the registry and gives it the URL of the remote object that it wants. The registry replies with a reference to the object that the client can use to invoke methods on the server.In reality, the client is only invoking local methods in a stub. The stub is a local object that implements the remote interfaces of the remote object; this means that the stub has methods matching the signatures of all the methods the remote object exports. In effect, the client thinks it is calling a method in the remote object, but it is really calling an equivalent method in the stub. Stubs are used in the client's virtual machine in place of the real objects and methods that live on the server; you may find it helpful to think of the stub as the remote object's surrogate on the client. When the client invokes a method, the stub passes the invocation to the remote reference layer.The remote reference layer carries out a specific remote reference protocol, which is independent of the specific client stubs and server skeletons. The remote reference layer is responsible for understanding what a particular remote reference means. Sometimes the remote reference may refer to multiple virtual machines on multiple hosts. In other situations, the reference may refer to a single virtual machine on the local host or a virtual machine on a remote host. In essence, the remote reference layer translates the local reference to the stub into a remote reference to the object on the server, whatever the syntax or semantics of the remote reference may be. Then it passes the invocation to the transport layer.The transport layer sends the invocation across the Internet. On the server side, the transport layer listens for incoming connections. Upon receiving an invocation, the transport layer forwards it to the remote reference layer on the server. The remote reference layer converts the remote references sent by the client into references for the local virtual machine. Then it passes the request to the skeleton. The skeleton reads the arguments and passes the data to the server program, which makes the actual method call. If the method call returns a value, that value is sent down through the skeleton, remote reference, and transport layers on the server side, across the Internet and then up through the transport, remote reference, and stub layers on the client side. In Java 1.2 and later, the skeleton layer is omitted and the server talks directly to the remote reference layer. Otherwise, the protocol is the same. |
• Table of Contents• Index• Reviews• Reader Reviews• Errata• AcademicJava Network Programming, 3rd EditionBy
Elliotte Rusty Harold Publisher: O'ReillyPub Date: October 2004ISBN: 0-596-00721-3Pages: 706
Thoroughly revised to cover all the 100+ significant updates
to Java Developers Kit (JDK) 1.5, Java Network
Programming is a complete introduction to
developing network programs (both applets and applications)
using Java, covering everything from networking fundamentals
to remote method invocation (RMI). It includes chapters on
TCP and UDP sockets, multicasting protocol and content
handlers, servlets, and the new I/O API. This is the
essential resource for any serious Java developer.

