Java Network Programming (3rd ed) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Java Network Programming (3rd ed) [Electronic resources] - نسخه متنی

Harold, Elliotte Rusty

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








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.*;
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;
}

Normally, this interface is limited to other programs running on that
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.


Object serialization is discussed in much greater detail in Chapter 11 of my previous book, Java
I/O (O'Reilly).


CORBA


RMI 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 Hood


The 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

To the programmer, the client appears to talk directly to the server.
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.


/ 164