To accomplish transparent transmission of objects from one address space to another, the technique of object serialization (designed specifically for the Java language) is used. Object serialization is described in this chapter only with regard to its use for marshaling primitives and objects. For complete details, see the specification Object Serialization in the Java System.
Another technique, called dynamic stub loading, is used to support client-side stubs which implement the same set of remote interfaces as a remote object itself. This technique, used when a stub of the exact type is not already available to the client, allows a client to use the Java language's built-in operators for casting and type-checking.
A remote method invocation from a client to a remote server object travels down through the layers of the RMI system to the client-side transport, then up through the server-side transport to the server.
A client invoking a method on a remote server object actually makes use of a stub or proxy for the remote object as a conduit to the remote object. A client-held reference to a remote object is a reference to a local stub. This stub is an implementation of the remote interfaces of the remote object and forwards invocation requests to that server object via the remote reference layer. Stubs are generated using the rmic compiler.
The remote reference layer is responsible for carrying out the semantics of the invocation. For example the remote reference layer is responsible for determining whether the server is a single object or is a replicated object requiring communications with multiple locations. Each remote object implementation chooses its own remote reference semantics-whether the server is a single object or is a replicated object requiring communications with its replicas.
Also handled by the remote reference layer are the reference semantics for the server. The remote reference layer, for example, abstracts the different ways of referring to objects that are implemented in (a) servers that are always running on some machine, and (b) servers that are run only when some method invocation is made on them (activation). At the layers above the remote reference layer, these differences are not seen.
The transport is responsible for connection set-up, connection management, and keeping track of and dispatching to remote objects (the targets of remote calls) residing in the transport's address space.
In order to dispatch to a remote object, the transport forwards the remote call up to the remote reference layer. The remote reference layer handles any server-side behavior that needs to be done before handing off the request to the server-side skeleton. The skeleton for a remote object makes an up-call to the remote object implementation which carries out the actual method call.
The return value of a call is sent back through the skeleton, remote reference layer and transport on the server side, and then up through the transport, remote reference layer and stub on the client side.
A stub for a remote object is the client-side proxy for the remote object. Such a stub implements all the interfaces that are supported by the remote object implementation. A client-side stub is responsible for:
Each remote object implementation chooses its own remote reference subclass that operates on its behalf. Various invocation protocols can be carried out at this layer, for example:
In a corresponding manner, the server-side component implements the specific remote reference semantics prior to delivering a remote method invocation to the skeleton. This component, for example, could handle ensuring atomic multicast delivery by communicating with other servers in the replica group.
The remote reference layer transmits data to the transport layer via the abstraction of a stream-oriented connection. The transport takes care of the implementation details of connections. Although connections present a streams-based interface, a connectionless transport may be implemented beneath the abstraction.
The transport for the RMI system consists of four basic abstractions:
To accomplish reference-counting garbage collection, the RMI runtime keeps track of all live references within each Java virtual machine. When a live reference enters a Java virtual machine its reference count is incremented. The first reference to an object sends a "referenced" message to the server for the object. As live references are found to be unreferenced in the local virtual machine, their finalization decrements the count. When the last reference has been discarded an unreferenced message is sent to the server. Many subtleties exist in the protocol, most related to maintaining the ordering of referenced and unreferenced messages to ensure the object is not prematurely collected.
When a remote object is not referenced by any client, the RMI runtime refers to it using a weak reference. The weak reference allows the Java virtual machine's garbage collector to discard the object if no other local references to the object exist. The distributed garbage collection algorithm interacts with the local Java virtual machine's garbage collector in the usual ways by holding normal or weak references to objects. As in the normal object life-cycle finalize
will be called after the garbage collector determines that no more references to the object exist.
As long as a local reference to a remote object exists, it cannot be garbage collected and it may be passed in remote calls or returned to clients. Passing a remote object adds the identifier for the virtual machine to which it was passed to the referenced set. A remote object needing unreferenced notification must implement the java.rmi.server.Unreferenced
interface. When those references no longer exist, the unreferenced
method will be invoked. unreferenced
is called when the set of references is found to be empty so it may be called more than once. Remote objects are only collected when no more references, either local or remote, still exist.
Note that if there exists a network partition between a client and remote server object, it is possible that premature collection of the remote object will occur (since the transport may think that the client crashed). Because of the possibility of premature collection, remote references cannot guarantee referential integrity; in other words, it is always possible that a remote reference may in fact not refer to an existing object. An attempt to use such a reference will generate a RemoteException
which must be handled by the application.
RMI generalizes this technique, using a mechanism called dynamic class loading to load at runtime (in the Java language's architecture neutral bytecode format) the classes required to handle method invocations on a remote object. These classes are:
rmic
compiler.)
main
method is run by using the java
command) from the local CLASSPATH. All classes used directly in that class are subsequently loaded by the default class loader from the local CLASSPATH.
java.rmi.server.codebase
property is used.
java.rmi.server.codebase
URL is used.
will be used to annotate that class in the stream if that class is used in an RMI call.
The application may be configured with the property java.rmi.server.useCodebaseOnly
, which disables the loading of classes from network hosts and forces classes to be loaded only from the locally defined codebase. If the required class cannot be loaded, the method invocation will fail with an exception.
RMISecurityManager
or user-defined security manager.
RMIClassLoader.loadClass
to load the class file for the client. The class name cannot be mentioned explicitly in the code, but must instead be a string or a command line argument. Otherwise, the default class loader will try to load the client class file from the local CLASSPATH.
newInstance
method to create an instance of the client and cast it to Runnable
. Thus, the client must implement the java.lang.Runnable
interface. The Runnable interface provides a well-defined interface for starting a thread of execution.
run
method (of the Runnable
interface).
import java.rmi.RMISecurityManager; import java.rmi.server.RMIClassLoader; public class LoadClient { public static void main() { System.setSecurityManager(new RMISecurityManager());
try { Class cl = RMIClassLoader.loadClass("myclient"); Runnable client = (Runnable)cl.newInstance(); client.run(); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); e.printStackTrace(); } } }
loadClass
method will use this URL to load the class, for example:java LoadClient -Djava.rmi.server.codebase=http://host/rmiclasses/
Class cl = RMIClassLoader.loadClass(url, "myclient");
Without this bootstrapping technique, all the classes directly referenced in the client code must be available through the local CLASSPATH on the client, and the only Java classes that can be loaded by the RMIClassLoader over the net are classes that are not referred to directly in the client program; these classes are stubs, skeletons, and the extended classes of arguments and return values to remote method invocations.
The security manger must be started as the first action of a Java program so that it can regulate subsequent actions. The security manager ensures that loaded classes adhere to the standard Java safety guarantees, for example that classes are loaded from "trusted" sources (for example, the applet host) and do not attempt to access sensitive functions. A complete description of the restrictions imposed by security managers can be found in the documentation for the AppletSecurity
class and the RMISecurityManager
class.
Applets are always subject to the restrictions imposed by the AppletSecurity
class. This security manager ensures that classes are loaded only from the applet host or its designated code base hosts. This requires that applet developers install the appropriate classes on the applet host.
Applications must either define their own security manager or use the restrictive RMISecurityManager
. If no security manager is in place, an application cannot load classes from network sources.
A client or server program is usually implemented by classes loaded from the local system and therefore is not subject to the restrictions of the security manager. If however, the client program itself is downloaded from the network using the technique described in Bootstrapping the Client, then the client program is subject to the restrictions of the security manager.
Even if a security manager is in place, setting the property java.rmi.server.useCodebaseOnly
to true prevents the downloading of a class from the URL embedded in the stream with a serialized object (classes can still be loaded from the locally defined java.rmi.server.codebase
). The java.rmi.server.useCodebaseOnly
property can be specified on both the client and the server, but is not applicable for applets.
If an application defines its own security manger which disallows the creation of a class loader, classes will be loaded using the default Class.forName
mechanism. Thus, a server may define its own policies via the security manager and class loader, and the RMI system will operate within those policies.
The java.lang.SecurityManager
abstract class, from which all security managers are extended, does not regulate resource consumption. Therefore the current RMISecurityManager
has no mechanisms available to prevent classes loaded from abusing resources. As new security manager mechanisms are developed, RMI will use them.
The more open server system will define its java.rmi.server.codebase
so that classes for the remote objects it exports can be loaded by clients and so that the server can load classes when needed for remote objects supplied by clients. The server will have both a security manager and RMI class loader which protect the server. A somewhat more cautious server can use the property java.rmi.server.useCodebaseOnly
to disable the loading of classes from client supplied URLs.
For example, the normal Applet scenario uses a single host for the HTTP server providing the HTML page, the Applet code, the RMI services, and the bootstrap Registry. In this scenario, all the stub, skeleton, and supporting classes are loaded from the HTTP server. All of the remote objects provided by the RMI service and passed to the Applet (which may pass them back to the server) will be for classes that the RMI service already knows about. In this case, the RMI service is very secure because it loads no classes from the network.
If an application is loaded locally, then the classes used directly in that program must also be available locally. In this scenario, the only classes that can be downloaded from a network source are the classes of remote interfaces, stub classes, and the extended classes of arguments and return values to remote method invocations.
If an application is not loaded from a local directory, but is itself loaded from a network source using the bootstrapping mechanism described in Bootstrapping the Client, then all classes used by the application can be downloaded from the same network source.
Even if a serialized object's class is annotated with the URL from which the class can be downloaded, a client or peer will still load classes locally if they are available.
java.rmi.server.RMISocketFactory
class to provide a default implementation of a socket factory which is the resource-provider for client and server sockets. This default socket factory creates sockets that transparently provide the firewall tunnelling mechanism as follows:java.rmi.server.RMISocketFactory.createSocket
method. Server-side sockets with this default behavior are provided by the factory's java.rmi.server.RMISocketFactory.createServerSocket
method.
The client can, however, disable the packaging of RMI calls as HTTP requests by setting the java.rmi.server.disableHttp
property to equal the boolean value true.
java.rmi.server.hostname
when starting the server.
ServerImpl
on the machine chatsubo.javasoft.com:
java -Djava.rmi.server.hostname=chatsubo.javasoft.com ServerImpl
Because HTTP requests can only be initiated in one direction through a firewall, a client cannot export its own remote objects outside the firewall, because a host outside the firewall cannot initiate a method invocation back on the client.
Copyright © 1996, 1997 Sun Microsystems, Inc., 2550 Garcia Ave., Mtn. View, CA 94043-1100 USA. All rights reserved.