CONTENTS | PREV | NEXT | Java Remote Method Invocation |
5.8 RMI Socket Factories
When the RMI runtime implementation needs instances ofjava.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 default transport's implementation of RMISocketFactory
provides for transparent RMI through firewalls using HTTP as follows:
- On
createSocket
, the factory automatically attempts HTTP connections to hosts that cannot be contacted with a direct socket. - On
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.
5.8.2 The RMIServerSocketFactory
Interface
See the RMIServerSocketFactory
API documentation. 5.8.3 The RMIClientSocketFactory
Interface
See the RMIClientSocketFactory
API documentation. CONTENTS | PREV | NEXT
Copyright 1997, 2010, Oracle and/or its affiliates. All rights reserved.