| CONTENTS | PREV | NEXT | Java Remote Method Invocation |
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:
RMISocketFactory.setSocketFactory.RMIClientSocketFactory and RMIServerSocketFactory, and then invoke the method UnicastRemoteObject.exportObject(Remote obj, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf). Alternatively, subclass the class UnicastRemoteObject and invoke the constructor UnicastRemoteObject(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf). This approach is more flexible than invoking the method RMISocketFactory.setSocketFactory because it enables you to export different objects bound to different interfaces. However, this approach is more complicated. The RMIClientSocketFactory implementation must be serializable because instances are transmitted to clients by being embedded in the stub. The RMIClientSocketFactory 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.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.RMISocketFactory Classjava.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 default
transport's implementation of RMISocketFactory
provides for transparent RMI through firewalls using HTTP as
follows:
createSocket, the factory automatically attempts HTTP
connections to hosts that cannot be contacted with a direct
socket.createServerSocket, the factory returns a server
socket that automatically detects if a newly accepted connection is
an HTTP POST request. If so, it returns a socket that will
transparently expose only the body of the request to the transport
and format its output as an HTTP response.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.
RMIServerSocketFactory InterfaceRMIServerSocketFactory API documentation.
RMIClientSocketFactory InterfaceRMIClientSocketFactory API documentation.