Please refer to lab 10 and the previous RMI lecture while studying the material presented below.
Plan:
Remote Method Invocation (RMI) is a pure-Java answer to remote procedure calls (RPC), and in some sense to the Distributed Component Object Model (DCOM) and the Common Object Request Broker Architecture (CORBA). All of these models are abstractions of distributing programs across the memory address space of a single machine, across multiple processors in a single machine, or across many machines on a network.
The RMI model attempts to make designing distributed applications as simple and straightforward as designing nondistributed applications. The programmer doesn't need to worry about sending data or translating data into objects, or any of the ugly stuff that the communication level is responsible for. The only concern is solid application design with minor attention paid to locating objects, as well as to handling some exceptions that are specific to network applications. The communication elements of the program have been abstracted to the point of seeming local. This abstraction frees you from the drudgery of writing low-level protocols and building objects based on data that you are reading over the network, but it can also be a little misleading.
It is simple to write an application that uses objects on remote machines. But although the programming interface makes it seem as if programming and application that uses only local objects, an application that uses remote objects is inherently different from an application that is entirely local. Some of the differences are:
Latency can be dealt with, to some degree, by carefully designing an application such that only those calls that must be made to a remote object are remote calls. The problems of full and partial failures can be dealt with only by giving careful consideration to exceptions and possible exceptional conditions that may arise during run time, and by dealing with them appropriately in the design of the application.
RMI was designed to make the design and implementation of network distributed applications almost like that of stand-alone object-oriented programs. No separate interface description language (IDL) is used to glue the parts together, everything is written in Java. In fact, RMI is a Java-specific model for writing distributed applications, unlike CORBA, which is intended to be language-neutral, or DCOM, which was designed with Microsoft's ActiveX architecture in mind.
What you give up in neutrality you make up in simplicity. A call to a remote object using RMI is identical to a call to a local object, with the following exceptions:
Remote object
Remote
interfaces that it (the remote object, that is) implements. A remote object can be cast
to any of the interfaces that it implements.
equals(), hashCode(), and toString()
methods, usually inherited by all objects in Java, have been overridden by
java.rmi.RemoteObject. These methods have been modified to deal
appropriately with a remote object. For example the equals method
checks if two object references are equal, not whether the contents are equal.
Also, the hashCode() method returns the same key for any references
that refer to the same remote object. The toString() method has been
modified to include information about the transport of the object, such as the
underlying network protocol, host name, and port number the object is coming from.
A remote method invocation is made through a reference to a remote object. The object is exported via a server application, and a handle to the object is obtained by a remote client either by looking up the object by name with a registry or by checking the return value from another remote method call.
This object must implement at least one interface
that extends the java.rmi.Remote interface. All interaction with the remote
object will be performed through this interface. Essentially, the interface describes the
methods that can be invoked remotely, and the remote object implements them.
When a reference to a remote object is obtained, the object is not sent over the network to the client requesting it. In its place is a proxy object or stub that is the client-side proxy for the remote object. All interactions by the client will be performed with/by this stub class. The stub is responsible for handing off data between the local system and the remote one. Many clients can have references to a single remote object. Each client will have its own stub object that represents the remote object, but the remote object will not be replicated.
On the server side a skeleton class is responsible for handing off the method calls and data to the actual object being referenced. This is the server-side proxy for the object being exported. The complete system can be though of as a four-layer model:
Interface Description
In many distributed programming models, you must define an interface to your remote objects
in an interface description language (IDL) and then run a special compiler or generator on
the IDL files that generates the files that your objects use to define their remote methods. In the
RMI model, all interfaces are described in Java. There is no need for a separate IDL. The necessary
files are generated directly from the compiled object code that implements remote interfaces. Namely,
the RMI stub compiler (rmic) is used to generate the special objects that are needed to
connect remote server objects to clients.
The Application Layer
An application that makes some of its methods available to remote clients must declare the methods in
an interface that extends java.rmi.Remote. The java.rmi.Remote interface is
an empty interface that declares no methods. Essentially it is used to flag an object as being remotely
accessible. When you want to define a set of methods that will be remotely called, they must be declared
in one or more interfaces that extend the java.rmi.Remote interface.
You implement a remote interface in the same way that you implement any other Java interface.
The only difference is some added exception handling for dealing with RemoteExceptions. These
are specific to remote calls and can be thrown if a problem arises in contacting or interacting with a remote
application.
Once the methods described in the remote interfaces have been implemented, the object must be exported.
This can be done implicitly if the object extends the UnicastRemoteObject class of the
java.rmi.server package, or it can be done explicitly with a call to the
exportObject() method of the same package.
Finally, the application will normally register itself with a name server, or registry. This is used to make first contact with the application and obtain a reference to its remote objects. Once first contact is made, any other remote object references that the server may want to export may be returned by method calls from the first object. Because of this, name service is generally only necessary upon application start-up.
On the client-side, a client simply requests a remote object from either a registry or a remote object
that it has already obtained. The reference to the remote object is cast to one of its Remote
interfaces, and any calls to remote methods can be made directly through this interface.
The Stub and Skeleton Layers
The stub and skeleton classes are generated using the RMI stub compiler, rmic. These are
simply class files that do the client- and server-side representations of a remote object.
The Stub Class
The stub is the client-side proxy for the remote object. The stub is the applications interface to the remote object; it is responsible for initiating a call to the remote object that it represents by way of the remote reference layer. The stub is also responsible for marshaling method arguments to a marshal stream that is also acquired through the remote reference layer. A marshal stream is simply a stream object that is used to transport parameters, exceptions, and errors needed for method dispatch and returning results. The stub and skeleton classes both use these streams for communicating with each other. The stub unmarshals values that have been returned by the remote object. This is also by way of the marshal stream. Finally, the stub class informs the remote reference layer that a call is complete.The Skeleton Class
Much like the stub classes, the skeleton classes marshal parameters to and from a marshal stream. The
difference is that the skeleton class stays on the server side of the connection and deals directly with
the implementation classes of the Remote methods being exported. The skeleton is responsible
for sending parameters to the method implementation and for sending return values and exceptions back to
the client that made the call. Essentially, the skeleton is responsible for receiving method calls from
a stub class, marshalling any necessary parameters, and dispatching the actual methods being exported. This
is the server-side proxy for the remote object.
The Remote Reference Layer
The remote reference layer is effectively the abstraction between the stub and skeleton classes and the actual communication protocols that are handled by the transport layer. The remote reference layer expects to get a stream-oriented connection from the transport layer. The actual transport may take place using a non-connection-based protocol, but interaction between the remote reference layer and the transport layer will take place as if it involved a stream, or connection-based protocol.
The remote interface layer will be used to handle replicated objects, once this feature is incorporated in the
RMI system. Replicated objects will allow simple dispatch to many programs that are exporting substantially the
same Remote objects. This layer will also be responsible for esatblishing persistence semantics and
strategies for recovery of lost connections.
The Transport Layer
The transport layer is responsible for handling the actual machine-to-machine communication. Because this communication is abstracted in this way, it allows system implementors to replace the low-level communications protocols with alternatives.
By default, communication will take place through a standard TCP/IP connection. The transport layer creates a stream that is accessed by the remote reference layer to send and receive data to and from other machines. The transport layer sets up connections to remote machines, manages the connections, monitors the connections to make sure that they are all 'live', and listens for connections from other machines.
The transport layer can be modified to handle encrypted streams, compression algorithms, and a number of other security- or performance-related enhancements. Because this layer is independent of the reference layer, the stub/skeleton layer, and the application layer, an RMI application does not need to know the specifics of any changes made to the transport layer.
The Object Hierarchy
Color codes: classes, interfaces.
myRemoteObject
+-extends----java.rmi.server.UnicastRemoteObject
| +-extends----java.rmi.server.RemoteServer
| +-extends----java.rmi.server.RemoteObject
| +-extends----java.lang.Object
| +-implements-java.rmi.Remote
+-implements myRemoteInterface
+-extends java.rmi.Remote
Name Service
In general itis necessary to bootstrap an applicaton that uses RMI. A server will register any remote objects that is exporting with a name server called a registry. When a client wishes to obtain a reference to a remote object, a URL-based lookup is performed on a well-known registry, and a reference to the remote object is returned if the lookup succeeds.
There are two ways of using the registry
services. The first is to follow the RPC model and maintain a registry server that is running on a well-known
port number. Any number of applications that export objects can register with this registry as long as they
are running on the same physical machine. A client can then look up the registered services via URLs passed
to certain lookup() and list() methods that query the registry. The second method
consists of an application running its own registry services. This allows the application to have complete
control over the registry but makes it more difficult to define a well-known port that will be used to access
remote objects.
Remote methods can be designed to return other remote objects. Because of this, it is generally necessary to contact a registry server only when making initial contact with an application. Once one of the remote objects on a server has been located, references to others can be obtained via method calls to the first object.
Garbage Collection
The distributed garbage collection algorithm used by the RMI system is a reference-counting algorithm. When a client first receives a reference to a remote object, a "referenced" message is sent to the server that is exporting the object. Every subsequent reference within the client's local machine causes a reference counter to be incremented. As a local reference is finalized, the reference count is decremented, and once the count goes to zero, an 'unreferenced' message is sent to the server. Once the server has no more live references to an object and there are no local references, it is free to be finalized and garbage collected.
If a remote object implements the java.rmi.server.Unreferenced interface, it must implement a body
for the unreferenced method. This method will be called once the object is no longer referenced.
It is also important to note that, under certain circumstance, such as network failure, an object may be collected
prematurely, because the transport layer may think that a connection to a machine containing a reference to the
object is no longer live. If this happens, subsequent attempts by the client to access the remote object will
result in a RemoteException being thrown.
Class Loaders
In Java, a class loader is responsible for dynamically loading the classes necessary for an application, as they are needed. This includes locating the files, locally or remotely, and retrieving them.
There
are different class loaders for different types of applications. For example a default class loader is used
to load locally run files. Applets have special security and class loader needs, so an
AppletClassLOader is used to load the classes necessary for an applet to
execute. Remote method invocation also has special requirements and normally employs the
RMIClassLoader. This class loader is responsible for loading the stub and
skeleton classes used by the RMI system, as well as any utility classes necessary for these
stubs and skeletons. In general, the RMIClassLoader will first attempt to load
classes that can be found on the local file system via the CLASSPATH environment
variable. If the classes cannot be found locally, the RMIClassLoader extracts a
URL that is included in a marshal stream of serialized objects. This URL is then used as the codebase
for locating the necessary classes. In the case of stub and skeleton classes a system property - the
java.rmi.server.codebaese property - is used to locate the necessary class files.
Security
The RMI run time requires that a security manager be explicitly set. The RMISecurityManager
is a direct descendant of java.lang.SecurityManager. It is used to set the security policies
used to givern the behaviour of the stub and skeleton classes.
Performance
If you intend to write video streaming applications, or other applications that require high network performance, RMI is probably not going to satisfy your needs. If you want to rapidly develop network applications and you can deal with increased latency, RMI is the way to go.
Summary
The RMI system is made up of a series of layers.Java API Quick ReferenceOn the application side, you have a remote interface that is implemented by a class that is exported in one of two ways - either by extending
UnicastRemoteObjector by passing a reference of itself toUnicastRemoteObject.exportObject().The next layer down is the stub/skeleton layer, which is generated from your compiled remote object using the
rmic. This generates a stub class to act as a client-side proxy and a skeleton class to act as server-side proxy, handling the work of dispatching the actual method calls. Finally you have an underlying transport layer that uses socket-based communications protocols to send data over the network.The system works with a registry name server for bootstrapping connections and has various facilities for RMI-specific class-loading and security mechanisms.
Remote method invocation describes a simple method for writing applications that can be distributed locally and over networks. Any object that is to be exported simply implements a
Remoteinterface, subclasses aRemoteObject(or exports itself using theUnicastRemoteObject.exportObject()method) and registers itself with a name service.A client can access a remote object by looking it up in a name service and then essentially working with it as if it were a local object.
java.rmi Package
java.rmi.dgc Package
java.rmi.registry Package
java.rmi.server Package
java.io Package (a subset)
java.rmi Exceptions
java.rmi Package
contains a Remote interface, a security manager,
and a Registry lookup and binding class. The
interface, java.rmi.Remote must be implemented
by any object that is exportable.
public interface Remote {
}
The Remote Interface is used to identify objects that
can be referenced remotely. The interface does not define any methods
or variables and is usually extended for particular applications. An
object that is exported is expected to implement this interface either
directly or indirectly through an extension. The only methods that are
available to a client using a remote object are declared in an interface
that extends Remote. The following is a simple example
that declares two methods that can be exported and remotely accessed:
public interface myRemote extends java.rmi.Remote {
public void remoteMeth1() throws RemoteException;
public void remoteMeth2() throws RemoteException;
}
Thepublic final class Naming extends Object
Naming class is used to interact with a registry. It contains
methods that can be used to add objects to a registry and to query a registry
for remote objects that have registered with it. Naming gives a
high-level, URL-based interface to registry servers. The Naming
class is final and and cannot be subclassed. If you wish to create your own
registry services, see the java.rmi.registry package. Constructors
The Naming class contains only static methods and does not define a constructor.
Fields
The Naming class does not define any public class variables.
Methods
public static void bind(String url, Remote obj)
throws AlreadyBoundException, MalformedURLException,
UnknownHostException, RemoteException
Used to register an object with a specified registry.
public static String[] list(String url)
throws RemoteException, MalformedURLException,
UnknownHostException
Used to query a registry for a list of remote objects that are
currently bound.
public static Remote lookup(String url)
throws NotBoundException, MalformedURLException,
UnknownHostException, RemoteException
Used to get a remote object from a registry server.
public static void rebind(String url, Remote obj)
throws RemoteException, MalformedURLException,
UnknownHostException
Used to replace an object that is already bound with the registry with the new
object specified with obj.
public static void unbind(String url)
throws RemoteException, NotBoundException,
MalformedURLException, UnknownHostException
Used to remove an object reference from the registry.
Thepublic final class RMISecurityManager extends SecurityManager
RMISecurityManager is a subclass of SecurityManager with certain
security policies that allow RMI to function. If a SecurityManager is not explicitly
set, an application will not be able to export objects over a network.
Constructors
public RMISecurityManager();Constructs and initializes an instance ofRMISecurityManager
Fields
RMISecurityManager does not declare any variables.
Methods checkAccept
checkAccess
checkConnect
checkConnect
checkConnect
checkCreateClassLoader
checkDelete
checkExec
checkExit
checkLink
checkListen
checkMemberAccess
checkPackageAccess
checkPackageDefinition
checkPrintJobAccess
checkPropertiesAccess
checkPropertyAccess
checkRead
checkRead
checkRead
checkRead
checkSecurityAccess
checkSetFactory
checkTopLevelWindow
CheckWrite
checkWriteGetSecurityContext
2. The java.rmi.dgc Package contains one interface and one class
that are used by the distributed garbage collection system. Garbage collection on distributed
systems has some unique needs that separate it from garbage collection in a single memory space.
The interface and class of this package will not generally be used by programmers using the RMI tools, but rather by system implementors who may want to create their own garbage collection algorithms.
3. The java.rmi.registry Package contains two interfaces and one
class that, together, are used to create, look up, and query a registry server. The class and
interfaces in this package can be used to create your own registry services, or to interact
with other registry services.
public interface Registry extends RemoteARegistryis used to locate RMI services.Field
Methodspublic final static int REGISTRY_PORTDefault port is1099.bindlistlookuprebindunbind
public interface RegistryHandlerMethodsregistryStubregistryImpl
public final class LocateRegistry extends ObjectTheLocateRegistryclass is used to locate registry servers and to create new ones. It is used to find registry services given an address or to create new ones given a port number.No constructors, no public variables.
Methods
createRegistrygetRegistry()getRegistry(int port)getRegistry(String host)getRegistry(String host, int port)
4. The java.rmi.server Package has most of the core classes
and interfaces that are necessary to export remote objects. This includes special class
loaders, socket factories, and remote object definitions that are subclassed to create
your own remote objects.
The java.rmi.server package also contains most of the classes needed for
implementing RMI, such as the stub and skeleton interfaces and the calling mechanism that
allow skeletons to communicate with the objects theyr represent. Many of the classes in
the server package are not used directly by programmers working with RMI but are part of
the low-level RMI system.
The main class in this package that is useful to you as a developer is the
UnicastRemoteObject class.
LoaderHandler
RMIFailureHandler
RemoteCall
RemoteRef
ServerRef
Skeleton
Unreferenced
TheLogStream
ObjID
Operation
RMIClassLoader
RMISocketFactory
RemoteObject
RemoteServer
RemoteStub
public class UnicastRemoteObject extends RemoteServer
UnicastRemoteObject class is the base class for most user-defined remote objects.
It supplies TCP-based point-to-point object references. Remote object implementations
that use UnicastRemoteObject are only valid for, at most, the lifetime of the process
that creates the remote object. Currently, UnicastRemoteObject is the only supported
implementation of the RemoteServer interface, and as such it is the only defined
mechanism for creating remote server objects. Constructor
protected UnicastRemoteObject() throws RemoteExceptionThis method constructs a newUnicastRemoteObject.
Fields
The UnicastRemoteObject class does not define any class variables.
Methods
Thepublic Object clone() throws CloneNotSupportedException
clone method is used to create an identical but separate copy of
this object.
public static RemoteStub exportObject(Remote obj)
throws RemoteException
This is used to export remote objects that do not subclass the UnicastRemoteObject
class directly. The object must implement a Remote interface. Upon
failure, a RemoteException is thrown. This method returns a stub for the exported
object. In early releases of the RMI system, remote objects had to be subclasses of
UnicastRemoteObject, but currently, nonsubclasses can be exported as long as they
implement a Remote interface and export themselves using the
exportObject() method of the UnicastRemoteObject class.
5. The java.io Package (a subset)
6. The java.rmi Exceptions