5 Server Interfaces
- The
RemoteObject
Class - The
RemoteServer
Class - The
UnicastRemoteObject
Class - The
Unreferenced
Interface - The
RMISecurityManager
Class - The
RMIClassLoader
Class - The
LoaderHandler
Interface - RMI Socket Factories
- The
RMIFailureHandler
Interface - The
LogStream
Class - Stub and Skeleton Compiler
The java.rmi.server
package contains interfaces and classes typically used to implement remote objects.
5.1 The RemoteObject
Class
See the RemoteObject
API documentation.
5.2 The RemoteServer
Class
See the RemoteServer
API documentation.
5.3 The UnicastRemoteObject
Class
The class java.rmi.server.UnicastRemoteObject
provides support for creating and exporting remote objects. The class implements a remote server object with the following characteristics:
- References to such objects are valid only for, at most, the life of the process that creates the remote object.
- Communication with the remote object uses a TCP transport.
- Invocations, parameters, and results use a stream protocol for communicating between client and server.
package java.rmi.server;
public class UnicastRemoteObject extends RemoteServer {
protected UnicastRemoteObject()
throws java.rmi.RemoteException {...}
protected UnicastRemoteObject(int port)
throws java.rmi.RemoteException {...}
protected UnicastRemoteObject(int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws java.rmi.RemoteException {...}
public Object clone()
throws java.lang.CloneNotSupportedException {...}
public static RemoteStub exportObject(java.rmi.Remote obj)
throws java.rmi.RemoteException {...}
public static Remote exportObject(java.rmi.Remote obj, int port)
throws java.rmi.RemoteException {...}
public static Remote exportObject(Remote obj, int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws java.rmi.RemoteException {...}
public static boolean unexportObject(java.rmi.Remote obj,
boolean force)
throws java.rmi.NoSuchObjectException {...}
}
5.3.1 Constructing a New Remote Object
A remote object implementation (one that implements one or more remote interfaces) must be created and exported. Exporting a remote object makes that object available to accept incoming calls from clients. For a remote object implementation that is exported as a UnicastRemoteObject
, the exporting involves listening on a TCP port (note that more than one remote object can accept incoming calls on the same port, so listening on a new port is not always necessary). A remote object implementation can extend the class UnicastRemoteObject
to make use of its constructors that export the object, or it can extend some other class (or none at all) and export the object via UnicastRemoteObject
's exportObject
methods.
The constructor that takes no arguments creates and exports a remote object on an anonymous (or arbitrary) port, chosen at runtime. The second form of the constructor takes a single argument, port, that specifies the port number on which the remote object accepts incoming calls. The third constructor creates and exports a remote object that accepts incoming calls on the specified port via a ServerSocket
created from the RMIServerSocketFactory
; clients will make connections to the remote object via Socket
s supplied from the RMIClientSocketFactory
.
Note that if you export a remote object without specifying a socket factory, or if you export the object with a version of the method UnicastRemoteObject.exportObject
or the constructor UnicastRemoteObject
that does not contain parameters of type RMIClientSocketFactory
and RMIServerSocketFactory
), then the remote object is exported to all local addresses. To export a remote object to a specific address, see the section "RMI Socket Factories".
5.3.2 Exporting an Implementation Not Extended From RemoteObject
An exportObject
method (any of the forms) is used to export a simple peer-to-peer remote object that is not implemented by extending the UnicastRemoteObject
class. The first form of the exportObject
method takes a single parameter, obj, which is the remote object that will accept incoming RMI calls; this exportObject
method exports the object on an anonymous (or arbitrary) port, chosen at runtime. The second exportObject
method takes two parameters, both the remote object, obj, and port, the port number on which the remote object accepts incoming calls. The third exportObject
method exports the object, obj, with the specified RMIClientSocketFactory
, csf, and RMIServerSocketFactory
, ssf, on the specified port.
The exportObject
method returns a Remote
stub which is the stub object for the remote object, obj
, that is passed in place of the remote object in an RMI call.
5.3.3 Passing a UnicastRemoteObject
in an RMI Call
As stated above, when an exported object of type UnicastRemoteObject
is passed as a parameter or return value in an RMI call, the object is replaced by the remote object's stub. An exported remote object implementation remains in the virtual machine in which it was created and does not move (even by value) from that virtual machine. In other words, an exported remote object is passed by reference in an RMI call; exported remote object implementations cannot be passed by value.
5.3.4 Serializing a UnicastRemoteObject
Information contained in UnicastRemoteObject
is transient and is not saved if an object of that type is written to a user-defined ObjectOutputStream
(for example, if the object is written to a file using serialization). An object that is an instance of a user-defined subclass of UnicastRemoteObject
, however, may have non-transient data that can be saved when the object is serialized.
When a UnicastRemoteObject
is read from an ObjectInputStream
using UnicastRemoteObject
's readObject
method, the remote object is automatically exported to the RMI runtime so that it may receive RMI calls. If exporting the object fails for some reason, deserializing the object will terminate with an exception.
5.3.5 Unexporting a UnicastRemoteObject
The unexportObject
method makes the remote object, obj, unavailable for incoming calls. If the force parameter is true, the object is forcibly unexported even if there are pending calls to the remote object or the remote object still has calls in progress. If the force parameter is false, the object is only unexported if there are no pending or in-progress calls to the object. If the object is successfully unexported, the RMI runtime removes the object from its internal tables. Unexporting the object in this forcible manner may leave clients holding stale remote references to the remote object. This method throws java.rmi.NoSuchObjectException
if the object was not previously exported to the RMI runtime.
5.3.6 The clone
method
Objects are only cloneable using the Java programming language's default mechanism if they support the java.lang.Cloneable
interface. The class java.rmi.server.UnicastRemoteObject
does not implement this interface, but does implement the clone
method so that if subclasses need to implement Cloneable
, the remote object will be capable of being cloned properly. The clone
method can be used by a subclass to create a cloned remote object with initially the same contents, but is exported to accept remote calls and is distinct from the original object.
5.4 The Unreferenced
Interface
package java.rmi.server;
public interface Unreferenced {
public void unreferenced();
}
The java.rmi.server.Unreferenced
interface allows a server object to receive notification that there are no clients holding remote references to it. The distributed garbage collection mechanism maintains for each remote object, the set of client virtual machines that hold references to that remote object. As long as some client holds a remote reference to the remote object, the RMI runtime keeps a local reference to the remote object. Each time the remote object's "reference" set becomes empty (meaning that the number of clients that reference the object becomes zero), the Unreferenced.unreferenced
method is invoked (if that remote object implements the Unreferenced
interface). A remote object is not required to support the Unreferenced
interface.
As long as some local reference to the remote object exists, it may be passed in remote calls or returned to clients. The process that receives the reference is added to the reference set for the remote object. When the reference set becomes empty, the remote object's unreferenced
method will be invoked. As such, the unreferenced
method can be called more than once (each time the set is newly emptied). Remote objects are only collected when no more references, either local references or those held by clients, still exist.
5.5 The RMISecurityManager
Class
See the RMISecurityManager
API documentation.
5.6 The RMIClassLoader
Class
See the RMIClassLoader
API documentation.
5.7 The LoaderHandler
Interface
See the LoaderHandler
API documentation.
5.8 RMI Socket Factories
When the RMI runtime implementation needs instances of java.net.Socket
and java.net.ServerSocket
for its connections, instead of instantiating objects of those classes directly, it calls the createSocket
and createServerSocket
methods on the current RMISocketFactory
object, returned by the static method RMISocketFactory.getSocketFactory
. This allows the application to have a hook to customize the type of sockets used by the RMI transport, such as alternate subclasses of the java.net.Socket
and java.net.ServerSocket
classes. The instance of RMISocketFactory
to be used can be set once by trusted system code. In JDK1.1, this customization was limited to relatively global decisions about socket type, because the only parameters supplied to the factory's methods were host
and port
(for createSocket
) and just port
(for createServerSocket
).
In the Java SE platform, the new interfaces RMIServerSocketFactory
and RMIClientSocketFactory
have been introduced to provide more flexible customization of what protocols are used to communicate with remote objects.
To allow applications using RMI to take advantage of these new socket factory interfaces, several new constructors and exportObject
methods, that take the client and server socket factory as additional parameters, have been added to both UnicastRemoteObject
and java.rmi.activation.Activatable.
Remote objects exported with either of the new constructors or exportObject
methods (with RMIClientSocketFactory
and RMIServerSocketFactory
parameters) will be treated differently by the RMI runtime. For the lifetime of such a remote object, the runtime will use the custom RMIServerSocketFactory
to create a ServerSocket
to accept incoming calls to the remote object and use the custom RMIClientSocketFactory
to create a Socket
to connect clients to the remote object.
The implementation of RemoteRef
and ServerRef
used in the stubs and skeletons for remote objects exported with custom socket factories is UnicastRef2
and UnicastServerRef2
, respectively. The wire representation of the UnicastRef2
type contains a different representation of the "endpoint" to contact than the UnicastRef
type has (which used just a host name string in UTF format, following by an integer port number). For UnicastRef2
, the endpoint's wire representation consists of a format byte specifying the contents of the rest of the endpoint's representation (to allow for future expansion of the endpoint representation) followed by data in the indicated format. Currently, the data may consist of a host name in UTF format, a port number, and optionally (as specified by the endpoint format byte) the serialized representation of an RMIClientSocketFactory
object that is used by clients to generate socket connections to remote object at this endpoint. The endpoint representation does not contain the RMIServerSocketFactory
object that was specified when the remote object was exported.
When calls are made through references of the UnicastRef2
type, the runtime uses the createSocket
method of the RMIClientSocketFactory
object in the endpoint when creating sockets for connections to the referent remote object. Also, when the runtime makes DGC "dirty" and "clean" calls for a particular remote object, it must call the DGC on the remote JVM using a connection generated from the same RMIClientSocketFactory
object as specified in the remote reference, and the DGC implementation on the server side should verify that this was done correctly.
Remote objects exported with the older constructor or method on UnicastRemoteObject
that do not take custom socket factories as arguments will have RemoteRef
and ServerRef
of type UnicastRef
and UnicastServerRef
as before and use the old wire representation for their endpoints, i.e. a host string in UTF format followed by an integer specifying the port number. This is so that RMI servers that do not use new 1.2 features will interoperate with older RMI clients.
If you export a remote object without specifying a socket factory, or if you export the object with a version of the method UnicastRemoteObject.exportObject
or the constructor UnicastRemoteObject
that does not contain parameters of type RMIClientSocketFactory
and RMIServerSocketFactory
, then the Java runtime uses the system's default RMI socket factory, which opens a socket on a wildcard address, which listens on all interfaces. Consequently, the remote object is exported to all local addresses. To export a remote object to a specific address, do one of the following:
Specify a socket factory with the method
RMISocketFactory.setSocketFactory
.Implement the interfaces
RMIClientSocketFactory
andRMIServerSocketFactory
, and then invoke the methodUnicastRemoteObject.exportObject(Remote obj, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf)
. Alternatively, subclass the classUnicastRemoteObject
and invoke the constructorUnicastRemoteObject(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf)
. This approach is more flexible than invoking the methodRMISocketFactory.setSocketFactory
because it enables you to export different objects bound to different interfaces. However, this approach is more complicated. TheRMIClientSocketFactory
implementation must be serializable because instances are transmitted to clients by being embedded in the stub. TheRMIClientSocketFactory
implementation classes must be made accessible to the client, typically by configuring the client's RMI codebase to point to where the classes are available.Instead of using one of the socket factories, set up a security policy that accepts incoming connections from only specific Internet addresses or domains. This option is flexible because it allows you to restrict access to specific networks, domains, or specific hosts (including only
localhost
). Note that with this approach, the Java runtime uses the system's default RMI socket factory that opens a socket that listens on all interfaces. The socket still accepts connections from disallowed hosts, domains, and networks, but it immediately closes these connections without processing any RMI requests.
5.8.1 The RMISocketFactory
Class
The java.rmi.server.RMISocketFactory
abstract class provides an interface for specifying how the transport should obtain sockets. Note that the class below uses Socket
and ServerSocket
from the java.net
package.
package java.rmi.server;
public abstract class RMISocketFactory
implements RMIClientSocketFactory, RMIServerSocketFactory
{
public abstract Socket createSocket(String host, int port)
throws IOException;
public abstract ServerSocket createServerSocket(int port)
throws IOException;
public static void setSocketFactory(RMISocketFactory fac)
throws IOException {...}
public static RMISocketFactory getSocketFactory() {...}
public static void setFailureHandler(RMIFailureHandler fh) {...}
public static RMIFailureHandler getFailureHandler() {...}
}
The static method setSocketFactory
is used to set the socket factory from which RMI obtains sockets. The application may invoke this method with its own RMISocketFactory
instance only once. An application-defined implementation of RMISocketFactory
could, for example, do preliminary filtering on the requested connection and throw exceptions, or return its own extension of the java.net.Socket
or java.net.ServerSocket
classes, such as ones that provide a secure communication channel. Note that the RMISocketFactory
may only be set if the current security manager allows setting a socket factory; if setting the socket factory is disallowed, a SecurityException
will be thrown.
The static method getSocketFactory
returns the socket factory used by RMI. The method returns null
if the socket factory is not set.
The transport layer invokes the createSocket
and createServerSocket
methods on the RMISocketFactory
returned by the getSocketFactory
method when the transport needs to create sockets. For example:
RMISocketFactory.getSocketFactory().createSocket(myhost, myport)
The method createSocket
should create a client socket connected to the specified host and port. The method createServerSocket
should create a server socket on the specified port.
The method setFailureHandler
sets the failure handler to be called by the RMI runtime if the creation of a server socket fails. The failure handler returns a boolean to indicate if retry should occur. The default failure handler returns false
, meaning that by default recreation of sockets is not attempted by the runtime.
The method getFailureHandler
returns the current handler for socket creation failure, or null
if the failure handler is not set.
5.8.2 The RMIServerSocketFactory
Interface
See the RMIServerSocketFactory
API documentation.
5.8.3 The RMIClientSocketFactory
Interface
See the RMIClientSocketFactory
API documentation.
5.9 The RMIFailureHandler
Interface
The java.rmi.server.RMIFailureHandler
interface provides a method for specifying how the RMI runtime should respond when server socket creation fails (except during object export).
package java.rmi.server;
public interface RMIFailureHandler {
public boolean failure(Exception ex);
}
The failure
method is invoked with the exception that prevented the RMI runtime from creating a java.net.ServerSocket
. The method returns true
if the runtime should attempt to retry and false
otherwise.
Before this method can be invoked, a failure handler needs to be registered via the RMISocketFactory.setFailureHandler
call. If the failure handler is not set, the RMI runtime attempts to re-create the ServerSocket
after waiting for a short period of time.
Note that the RMIFailureHandler
is not called when ServerSocket
creation fails upon initial export of the object. The RMIFailureHandler
will be called when there is an attempt to create a ServerSocket
after a failed accept on that ServerSocket
.
5.10 The LogStream
Class
See the LogStream
API documentation.
5.11 Stub and Skeleton Compiler
The rmic
stub and skeleton compiler is used to compile the appropriate stubs and skeletons for a specific remote object implementation.
Please see the following URLs for further information on rmic
:
- For the Linux and Mac Operating System:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/rmic.html
- For the Windows platform:
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/rmic.html