|
Remote Method Invocation is Java's
"objectization" of the usual Remote Procedure Call
capablilites of most modern server-capable operating systems such as
Unix or Windows NT. RMI enables a client computer
to access an object located in a remote server as if it were a
locally instantiated object in the client.
Features:
- Both the client and server are pure
object-oriented systems. The interaction between the
server and the client is encapsulated in one or more remotely
accessible objects. These objects are instantiated
on the server, but the client treats the object as if they were
local instantiations.
- Once the inital communication between
the server and client has been established, all further
communications are completely transparent to both the client and
the server.
- Just as in the methods of ordinary
objects, the methods of remote objects can take objects as
inputs and return them. There are a couple of things
to note:
- Ordinary objects that are passed as
arguments or returned by the methods must implent Serializable. This enables them to
be sent as a data stream across the network.
Only the data and not the executable code for objects is
passed, thus both the client and server must have a copy of
the class file for that object.
- Remote objects can be passed from the server to the client as
the return value of a method. In this case, the object
is not actually transmitted, but rather, just a stub
(see below and the link to the left).
- Initial communications between the
client and server is established through simple URL-type
addressing with minimal references to any underlying
communications mechanisms or protocols.
Main Components:
- A "client"
computer and a "server" computer: The remote object resides on the server and is
accessed by the client. Note that the
roles of client and server are not permanent and may change/reverse
depending on which computer accesses a remote object stored on
another computer. It is possible for a single computer
to be both a client and a server.
- An
interface that implements Remote: This is the view of the remote
object by the client. To the
client, the remote object on the server is a local object
with the specified interface. All clients accessing the remote object must have
a local copy of the same
interface class unless the new dynamic loading schemes in Java 2 are
utilized.
- An
instantiation of a class that extends UnicastRemoteObject and
implements the same interface given in #2
above: This is the remotely accessible
object that resides on the server.
- A
"stub" object created by the rmic program on the above remote object's class
file: This object resides on the
server and is transmitted to the client whenever a reference to the
remotely accessible object is established. This is the actual
object that the client interacts with. The stub object simply
delegates all methods call across the network to its corresponding
skeleton object on the server.
- A
"skeleton" object created by the rmic program from the above remote object
class: This object resides on the server
and delegates method requests received across the network from the stub
object to the actual remote object.
Note:
JBuilder 4 will automatically run rmic on those files designated
for sub and skeleton creation. Right click the file and look
under Properties/Build.
- The RMI
Registery: This is a program on the server called
rmiregistry that must be running before
any RMI connection is established. This program
associates an instatiation of a remote object with a name
that can accessed with a URL-type call. A name is
"bound" into the RMI registry by using Java's built-in
method:
void Naming.bind(String
aName, UnicastRemoteObject aRemoteObject)
This is
how the first connection to the first remote object is
established. Usually that first object is a "factory" design class
that has methods to return references to other remote
objects. This recommended "bootstrapping" technique keeps a
minimum number of names in the RMI registry.
Note: JBuilder 4 can
run the RMIRegistry directly. Click
on Tools/RMIRegistry.
Example (needs to be in a
try-catch block): Naming.bind("MRO,new
MyRemoteObject());
- Naming.lookup(): The reference
to the remote object can be established either by using Java's built-in
method:
Remote
Naming.lookup(String aRMI_URL)
Or the reference can simply
be a return value from a previously established remote object
reference's method (e.g. a factory method).
Example (needs
to be in a try-catch block): IMyRemoteObject mRO = (IMyRemoteObject)
Naming.lookup("rmi://foo.cs.oberlin.edu/MRO");
-
Dynamic Class Loading: If the client does not have
the class file for the serializable object being sent, it will try to to
download the class file from the location specified by the java.rmi.server.codebase system property that is
imbedded in the serialized object. Sun has written a simple class
file server that can be used for dynamic class loading. That
code is provided here in a slightly modified version. It will work
properly only if the java.rmi.server.codebase system property is as a
URL that points to it. For example, http://foo.cs.oberlin.edu:2001.
The server also needs to know the exact path to the default Java package
directory on the server machine. Note: If both the
client and the server have classes with exactly the same name, errors
(usually unmarshalling errors) can occur. It is highly
recommended that the names of any serialized classes
being sent across the RMI connection be "personalized" in some
way--by appending one's initials to the classname for
instance. This problem can be avoided by carefully
setting up exactly what directories are visible to the RMIRegistry,
class server and application when they are running, but that is beyond
the scope of this web page. See one of the several O'Reilly
books that contain sections dealing with RMI for more
information.
Example:
An RMI Chat program
This program uses RMI to establish a
connection between two computers and send messages back and
forth between them. The user types in one text area and
then clicks "Send." A copy of their
message, echoed from the remote machine, will then appear in the
output window. When the other party sends a message,
the message will appear in the output window as well.
The program uses a full Model-View-Controller architecture and
includes extra files that could be used to revamp
the interface to allow automatic connections and multiple, simultaneous chat sessions.
See documentation for RMIChat program, including the class
server
Get source code for all the RMIChat program
pieces
See the documentation for
class server needed to support RMI's dynamic class loading
capability.
Basic Development Procedure:
- JBuilder only: Right-click the files
that extend UnicastRemoteObject. Right
click the file and look under Properties/Build.
Select and check off "Generate RMI stub/skeleton".
- Compile all code. Note: For peer-to-peer connections,
the client and server code will be running on separate threads.
- Non-JBuilder only: Run rmic [your
Remote objects] to create the stubs and skeletons.
- Non-JBuilder: In Windows, run start rmiregistry to start the RMI registry up in its
own window and process. In Unix, run rmiregistry & to accomplish the
same. Type Ctrl-C in the RMI registry window to
kill it when desired.
- JBuilder: Start the
rmiregistry by clicking on "Tools/RMIRegistry".
- The class server must be
started before any objects are bound to the
RMIRegistry!
- Peer-to-Peer system:
- On all machines involved, run start rmiregistry (Windows) to
start the RMI registry up in its own window and
process. In Unix, run rmiregistry & to accomplish the same.
Type Ctrl-C in the RMI
registry window to kill it when desired.
- Run your Java program as normal on
all machines.
- Pure Client-Server system:
- On the server machine only , run start rmiregistry
(Windows)to
start the RMI registry up in its own window and
process. In Unix, run
rmiregistry &to accomplish the same.
Type
Ctrl-C in the RMI
registry window to kill it when desired.
-
Run
start
java [your server app](
java
[your server app] &in Unix) on your server to start
your server process.
-
Run your client Java program
as normal on the client machine(s).
Warnings:
-
RMI is
extremely
picky about the JDK being used.
Use the same JDK for all machines, at least ver. 1.1.6
. Be sure that Sun's JDK is first on
the classpath and regular path
(before Visual Cafe's for
example).
- Visual Cafe will not run either rmic nor rmiregistry automatically for programs
involving remote objects. Be sure to manually run these
programs when needed.
- JBuilder will run rmic automatically only
for files whose "Java Source" properties (right click the
filename in the project listing) is set to generate the stubs and
skeletons. The rmiregistry can be run
from inside of JBuilder (under the Tools menu).
- RMI does not wait for the return of a remote void
method call to return before proceeding on to the next
statement. This can cause some strange behaviors if the code
assumes a certain order of execution based on the assumption that the
call to the void method waits for it to finish, as normally happens in a
non-RMI, single-threaded situation. For instance, the following
code can cause problems:
// in ObjectA, initially call method1()
below. remoteObjectB is a RMI stub to a remote ObjectB
instance.
void method1() {
remoteObjectB.doIt();
System.out.println("the statement after the call to
remoteObjectB"); } void
method2() { System.out.println("this might come
out first or second!"); // This will mostly likely
come out second due to network delays. // In a non-RMI,
single-threaded situation, this line would print first. }
// The following is in class ObjectB which holds an RMI stub to the
above ObjectA instance.
void
doIt() {
remoteObjectA.method2(); }
Factories and RMI
Factories are one of the most useful techniques to use with
RMI. Usually the server only binds out one object, a factory
object, which the client uses to instantiate all the other objects it
actually needs. This makes connecting much
simpler, more flexible and more robust.
This technique is important enough that Sun even has a whole web page
devoted to it: http://java.sun.com/j2se/1.3/docs/guide/rmi/Factory.html
RMI FAQ
http://java.sun.com/products/jdk/1.2/docs/guide/rmi/faq.html
|