Skip navigation links

Package net.jini.jeri

Provides the fundamental abstractions and standard implementation classes for Jini extensible remote invocation (Jini ERI).

See: Description

Package net.jini.jeri Description

Provides the fundamental abstractions and standard implementation classes for Jini extensible remote invocation (Jini ERI).

Jini ERI is an implementation of the Java(TM) Remote Method Invocation (Java RMI) programming model that supports the following features:

In addition, Jini ERI supports full Java RMI dynamic class loading semantics.

This package includes the standard class for exporting remote objects with Jini ERI, the interfaces that define the Jini ERI architectural elements, standard implementation classes for some of those interfaces, and a standard trust verifier class.

Programming Model

In general, applications are not expected to program directly to Jini ERI APIs for exporting remote objects; instead, applications should program to the Exporter interface, and exporters should normally be obtained from a Configuration. The application developer should document the requirements that a given configurable exporter must satisfy, so that the application deployer can provide an exporter that meets those requirements. See the net.jini.config package documentation for examples of configurable exporting.

Server-side remote method authorization checks should generally be implemented by the exporter, not by the remote object implementation, so that the authorization policy can be customized by the application deployer.

Clients should program to the RemoteMethodControl interface for setting invocation constraints on proxies and generally should not make assumptions about how proxies are implemented.

Protocol Stack

The Jini ERI architecture has a protocol stack with three layers as shown in the following table, with interfaces representing the abstractions of each layer on the client side and the server side as shown:

Layer Client-side abstractions Server-side abstractions
Invocation layer InvocationHandler InvocationDispatcher
Object identification layer ObjectEndpoint RequestDispatcher
Transport layer Endpoint, OutboundRequestIterator, OutboundRequest ServerCapabilities, ServerEndpoint, InboundRequest

The client-side and server-side implementations of each layer are chosen for a particular remote object as part of exporting the remote object. The design is intended to allow plugging in different implementations of one layer without affecting the implementations of the other layers.

The client side abstractions correspond to the structure of the client-side proxy for a remote object exported with Jini ERI, with the invocation layer implementation containing the object identification layer implementation and that, in turn, containing the transport layer implementation.

Which invocation constraints are supported for remote invocations to a particular remote object exported with Jini ERI is partially dependent on the particular implementations of these layers used for the remote object (most especially the transport layer implementation).

Exporter

An Exporter exports a remote object and returns a proxy for making remote invocations on the exported remote object. The standard Jini ERI exporter class is BasicJeriExporter, which is suitable for most applications. BasicJeriExporter by itself exports non-activatable remote objects; to export an activatable remote object with Jini ERI, an ActivationExporter can be used with a BasicJeriExporter as its underlying exporter.

A BasicJeriExporter is constructed with the information for controlling the client-side and server-side implementations of all layers of the Jini ERI protocol stack for the remote object to be exported:

BasicJeriExporter implies use of a particular implementation of the object identification layer: BasicObjectEndpoint as the ObjectEndpoint implementation on the client side and an internal RequestDispatcher implementation on the server side. The object identifier and flags of a BasicJeriExporter control features of this standard object identification layer implementation. The nature of the object identification layer is such that the need to use a different implementation should be rare. In order to use a different implementation of the object identification layer, a deployer needs to use a custom Jini ERI exporter class, which should support specifying an InvocationLayerFactory and ServerEndpoint for controlling the invocation and transport layer implementations.

For a given remote object exported with Jini ERI, the client-side and server-side counterparts at each layer of the protocol stack must be compatible in order for remote invocations to succeed. At the transport layer, obtaining the client-side Endpoint from the supplied server-side ServerEndpoint ensures compatibility. At the object identification layer, BasicJeriExporter always uses compatible ObjectEndpoint and RequestDispatcher implementations. At the invocation layer, the InvocationLayerFactory abstraction is used to facilitate generation of compatible InvocationHandler and InvocationDispatcher pairs.

The proxy returned by a BasicJeriExporter (a Jini ERI proxy) is an instance of a dynamic proxy class with the following typical structure:

The proxy object is ultimately created by the InvocationLayerFactory supplied to the exporter. The proxy class typically implements all of the remote interfaces of the remote object's implementation class, plus RemoteMethodControl and any extra interfaces chosen by the factory. The server constraints in the invocation handler are set by the factory, which typically allows specifying them with a constructor argument. The client constraints are initially null and can be set using RemoteMethodControl.setConstraints on the proxy.

The BasicObjectEndpoint is constructed with the object identifier in the exporter and the Endpoint, which is obtained from the ServerEndpoint by invoking its enumerateListenEndpoints method.

Invocation Layer

The invocation layer deals with the concepts of methods, arguments, return values, and exceptions; marshalling and unmarshalling objects; and remote invocation semantics generally. The invocation layer drives the remote invocation process on the client side.

On the client side, when a remote method is invoked on a Jini ERI proxy, it reflectively dispatches the method invocation to the contained invocation handler. The invocation handler for a Jini ERI proxy typically performs the following steps to carry out its role in processing a remote call:

On the server side, when the RequestDispatcher receives a remote call request for a particular remote object, it dispatches that request to the InvocationDispatcher that the remote object was exported with, passing the remote object, an InboundRequest for performing I/O on the request, and a collection of server context elements. An invocation dispatcher typically performs the following steps to carry out its role in processing a remote call: Authorization checks are made before any arguments are unmarshalled in order to avoid denial of service attacks that could be mounted using serialization mechanisms or dynamically loaded classes.

If the Integrity.YES constraint is being enforced for a remote call, the marshal input streams created on both sides enforce code integrity using Security.verifyCodebaseIntegrity.

BasicInvocationHandler and BasicInvocationDispatcher are standard invocation handler and invocation dispatcher classes that are suitable for most applications. Both BasicInvocationHandler and BasicInvocationDispatcher are designed to be extensible so that subclasses can augment or replace how many of the above steps are performed. For example, a subclass could perform additional authorization checks based on the actual arguments; marshal or unmarshal data in an alternate context; perform pre- or post-processing on the arguments, return value, or exception; or cooperate with a corresponding subclass to marshal and unmarshal additional implicit data with a remote call.

As described above, the InvocationLayerFactory interface is an abstraction for an object that produces the client-side and server-side implementations of the invocation layer for a remote object at export time. An InvocationLayerFactory must produce compatible client-side and server-side invocation layer implementations. BasicILFactory is a standard implementation of InvocationLayerFactory that produces a proxy with a BasicInvocationHandler and an invocation dispatcher that is a BasicInvocationDispatcher. A BasicILFactory is sufficient when no customizations of BasicInvocationHandler and BasicInvocationDispatcher are desired. Custom invocation handler and invocation dispatcher implementations (such as subclasses of BasicInvocationHandler and BasicInvocationDispatcher) can be used by passing a custom InvocationLayerFactory to the exporter. AbstractILFactory is a convenience class for writing such custom InvocationLayerFactory implementations.

The authorization mechanism provided by BasicInvocationDispatcher uses the standard Permission model. A permission class can be specified to the BasicILFactory constructor and is passed to the BasicInvocationDispatcher constructor at export time. The permission class is typically a simple subclass of AccessPermission. The invocation dispatcher constructs an instance of the specified permission class based on the remote method being invoked. For each incoming remote call, the client subject must be granted the permission for that remote method or the remote call will be refused.

Object Identification Layer

The object identification layer identifies distinct remote objects that are exported to a given transport endpoint and implements behavior that is specific to individual exported remote objects (but not to the remote invocation semantics of those objects), such as distributed garbage collection.

Typically, an ObjectEndpoint contains an object identifier for the remote object as well as the Endpoint for communicating requests to the remote object, and a RequestDispatcher contains a table mapping object identifiers to exported remote objects.

On the client side, an ObjectEndpoint typically prepends the object identifier to the remote call request data for reading by the corresponding RequestDispatcher. The executeCall method typically reads from the beginning of the response an indication from the RequestDispatcher of whether or not the identified object was found, and if it was not, returns a NoSuchObjectException for the remote invocation to throw.

On the server side, when the transport layer receives a request, it dispatches that request to the RequestDispatcher for the communication endpoint that the request was received on, passing an InboundRequest for performing I/O on the request. The RequestDispatcher typically reads the object identifier from the beginning of the request data and looks for a remote object with that identifier in its table of exported objects. If such an object is found, the associated InvocationDispatcher is invoked with the remote object, the InboundRequest, and a server context collection populated by the InboundRequest. If no such object is found, an indication is written to the response output stream for reading by the corresponding ObjectEndpoint.

The invocation dispatcher is invoked inside an invocation of ServerContext.doWithServerContext with an unmodifiable view of the server context collection described above, so that the context is available to the remote object implementation.

BasicJeriExporter uses BasicObjectEndpoint instances for the client-side object identification layer implementation and instances of an internal RequestDispatcher class for the server-side object identification layer implementation. This object identification layer implementation supports distributed garbage collection, as described below.

Transport Layer

The transport layer communicates requests and responses over the network. The transport layer drives the dispatching of remote call requests on the server side, and thus it controls the server-side threading model.

The transport layer provides abstractions for request/response-based communication, where a request and its corresponding response are each a binary sequence of bytes. While the transport communication is represented to higher layers as discrete requests and responses, connection-oriented communication will be a common implementation technique. The net.jini.jeri.connection package provides support for implementing connection-based transport layer providers.

An OutboundRequest represents a request being sent, providing an OutputStream for writing the request and an InputStream for reading the response. An InboundRequest represents a request being received, providing an InputStream for reading the request and an OutputStream for writing the response.

The ServerEndpoint interface is the server-side transport layer abstraction for one or more communication endpoints on the local host to listen for and receive requests on. The individual communication endpoints are represented as ListenEndpoint instances during an invocation of the ServerEndpoint.enumerateListenEndpoints method. A ServerEndpoint contains the network location for receiving remote call requests. For example, a TCP-based ServerEndpoint typically contains the TCP port to bind to. A ServerEndpoint that supports authentication typically contains the Subject to use for server authentication. The subject is normally obtained from the current thread when the server endpoint is constructed.

The Endpoint interface is the client-side transport layer abstraction for a remote communication endpoint to sent requests to. An Endpoint contains the network location for the remote object. For example, a TCP-based Endpoint typically contains the remote host address and TCP port to connect to.

The enumerateListenEndpoints method is invoked on a ServerEndpoint by an exporter at export time to start or reuse listen operations on the communication endpoints represented by the ServerEndpoint. The exporter's ListenContext, which is passed to enumerateListenEndpoints, starts new listen operations when necessary by passing a RequestDispatcher to the ListenEndpoint instances that are enumerated. The enumerateListenEndpoints invocation returns an Endpoint that corresponds to the listen operations started or chosen by the exporter, and that Endpoint is used in the Jini ERI proxy produced by the export. When a request is received for any active listen operation, an InboundRequest is created to communicate that request and is passed to the RequestDispatcher associated with the listen operation.

When the Endpoint.newRequest method is invoked to send a new request, it returns an OutboundRequestIterator, which may be able to produce one or more OutboundRequest instances for attempting to send the request. OutboundRequestIterator is designed to allow an Endpoint implementation to offer multiple communication mechanism alternatives to try or to otherwise signal to higher layers that a request should be retried.

The net.jini.jeri.tcp package provides transport over TCP/IP. The net.jini.jeri.http package provides HTTP transport over TCP/IP, for use through firewalls. The net.jini.jeri.ssl package provides two TLS/SSL-based transports: TLS/SSL transport over TCP/IP, and HTTPS (HTTP over TLS/SSL) transport over TCP/IP, for use through firewalls. The net.jini.jeri.kerberos package provides Kerberos-based transport over TCP/IP.

Invocation Constraints

As described above, a Jini ERI proxy is typically an instance of RemoteMethodControl and contains client and server MethodConstraints for controlling the InvocationConstraints that apply to each remote method. When a remote method is invoked on the proxy, the invocation handler combines the InvocationConstraints for that method from the client and the server MethodConstraints and converts relative time constraints to absolute time constraints, to form the InvocationConstraints to use for the remote call. If any of the requirements cannot be satisfied, the remote invocation throws an UnsupportedConstraintException.

The server MethodConstraints are specified at export time, via the InvocationLayerFactory supplied to the exporter, and are stored in the invocation dispatcher on the server side and in the invocation handler on the client side. The ServerCapabilities interface represents the server-side transport layer implementation to the invocation dispatcher for the purpose of verifying, at export time, that the entire implementation of the protocol stack supports the server constraints that that remote object is being exported with. (Otherwise, constraint misconfigurations could go undetected on the server side.) ServerEndpoint extends ServerCapabilities so that an invocation dispatcher does not need to be programmed to the ServerEndpoint API explicitly. At export time, the ServerEndpoint is passed to the InvocationLayerFactory as a ServerCapabilities, and the InvocationDispatcher created by the factory invokes ServerCapabilities.checkConstraints with all possible InvocationConstraints in the server MethodConstraints.

The initial client MethodConstraints of a Jini ERI proxy, upon return from an exporter, are null. Client MethodConstraints can be set for a Jini ERI proxy by invoking RemoteMethodControl.setConstraints on the proxy to obtain a new copy of the proxy with the specified client MethodConstraints.

Most constraints are fully implemented by the transport layer, but there is limited support for constraints being implemented by higher layers. For any given constraint, there must be a clear delineation of which aspects (if any) must be implemented by the transport layer. Most of the constraints in the net.jini.core.constraint package must be fully implemented by the transport layer; the one exception is Integrity, for which the transport layer is responsible for the data integrity aspect and the invocation layer is responsible for the code integrity aspect.

On both sides, the transport layer is first given the opportunity to implement the constraints in force for a given remote call. The transport layer returns to the invocation layer any constraints that must be at least partially implemented by higher layers: on the client side, as the return value of OutboundRequest.getUnfulfilledConstraints, which is invoked by the invocation handler before marshalling the remote call, and on the server side, as the return value of InboundRequest.checkConstraints, which is invoked by the invocation dispatcher before unmarshalling the remote call.

Proxy Trust

On the client side, secure proxies need to be trusted to correctly carry out remote calls. In order to verify that a proxy can be trusted, a client passes it to Security.verifyObjectTrust, which uses locally configured TrustVerifier instances to determine if the proxy and (in recursive trust verification operations) its constituent objects can be trusted.

BasicJeriTrustVerifier can be used as a trust verifier for a Jini ERI proxy that uses BasicInvocationHandler and BasicObjectEndpoint, whose dynamic proxy class is defined by a locally trusted class loader, and whose server constraints and Endpoint are themselves trusted. ConstraintTrustVerifier can be used as a trust verifier for instances of many standard constraint classes. The Endpoint needs to be trusted to correctly carry out communication with all of the constraints that it supports; SslTrustVerifier can be used as a trust verifier for SslEndpoint and HttpsEndpoint instances, and KerberosTrustVerifier can be used as a trust verifier for KerberosEndpoint instances.

Typically, the dynamic proxy class for a Jini ERI proxy received from a remote party will be defined by a class loader that is not directly trusted by BasicJeriTrustVerifier (or any other local trust verifier), so the proxy cannot be trusted directly by clients. If a Jini ERI proxy satisfies all of BasicJeriTrustVerifier's conditions for trust except the condition regarding its dynamic proxy class's loader, then (on the assumption that the parent of that loader will be locally trusted) ProxyTrustVerifier can be used as a trust verifier for the proxy, with the proxy itself serving as the bootstrap proxy in ProxyTrustVerifier's algorithm. In order to support this intention, ProxyTrustILFactory can be used to cause the proxy to be an instance of ProxyTrust (in addition to RemoteMethodControl and the remote object's remote interfaces) so that it qualifies as a bootstrap proxy, and then the remote object would implement ServerProxyTrust.getProxyVerifier to return a verifier for the proxy.

If a Jini ERI proxy that could be trusted by clients (perhaps by ProxyTrustVerifier as described previously) is contained within a proxy that will not be trusted directly by clients, then ProxyTrustVerifier can be used as a trust verifier for the outer proxy, with the contained Jini ERI proxy serving as the bootstrap proxy. The outer proxy would need to be implemented to conform to the requirements of the algorithm specified by ProxyTrustVerifier, such as by having a getProxyTrustIterator method that returns an iterator that produces the Jini ERI proxy. ProxyTrustILFactory can be used to cause the Jini ERI proxy to be an instance of ProxyTrust, and then the remote object would implement ServerProxyTrust.getProxyVerifier to return a verifier for the outer proxy.

If a Jini ERI proxy contains custom component objects (such as a custom invocation handler or custom Endpoint) that will not be trusted directly by clients, then ProxyTrustExporter can be used to combine that proxy with a trustable bootstrap proxy, such that the client can use ProxyTrustVerifier to verify that the aggregate proxy can be trusted. The remote object would then implement ServerProxyTrust.getProxyVerifier to return a verifier for the aggregate proxy. ProxyTrustExporter can be used similarly if a Jini ERI proxy containing custom component objects is contained within another proxy that will not be trusted directly by clients.

Distributed Garbage Collection

BasicJeriExporter supports exporting remote objects that participate in distributed garbage collection (DGC).

DGC uses a two-stage reference counting algorithm to maintain referential integrity across virtual machines, for remote objects exported with DGC enabled:

Because a reference counting algorithm is used, collection of unreachable cycles of remote references is not supported.

If a remote object that is an instance of Unreferenced is exported with DGC enabled, then whenever the number of DGC clients that are known to have live remote references to the remote object transitions from greater than zero to zero, the remote object's unreferenced method is invoked (before the server-side implementation's strong reference is dropped).

The referential integrity of the live remote references tracked by a given DGC client to a given server-side DGC implementation is leased for finite durations of time. The lease duration is chosen by the server-side implementation and conveyed in dirty call responses. The DGC client is responsible for renewing its lease with the server (with successive dirty calls) as long as it has live remote references for that server. If the server-side DGC implementation detects a lease expiration, it no longer considers the DGC client to have live remote references to any of its exported remote objects. This leasing model is designed to allow server-side cleanup and garbage collection in the event of client failure, at the expense of possible loss of referential integrity in the event of communication failure.

See the BasicObjectEndpoint and BasicJeriExporter specifications for more information about client-side and server-side DGC processing.

Since:
2.0
Version:
3.0
Skip navigation links

Copyright 2007-2013, multiple authors.
Licensed under the Apache License, Version 2.0, see the NOTICE file for attributions.