In the RMI activation protocol, there
are two guarantees that the activator must make for the system to
function properly:

like all system daemons, the
activator should remain running while the machine is up, and

the activator must not reactivate
remote objects that are already active.

The activator maintains a database of
appropriate information for the groups and objects that it
participates in activating.

7.4.1 The
Activator Interface

The activator is one of the entities
that participates during the activation process. As described
earlier, a faulting reference (inside a stub) calls the
activator's activate method to obtain a
"live" reference to an activatable remote object. Upon
receiving a request for activation, the activator looks up the
activation descriptor for the activation identifier, id,
determines the group in which the object should be activated, and
invokes the newInstance method on the activation
group's instantiator (the remote interface
ActivationGroup is described below). The activator
initiates the execution of activation groups as necessary. For
example, if an activation group for a specific group descriptor is
not already executing, the activator will spawn a child JVM for the
activation group to establish the group in the new JVM.

The activator is responsible for
monitoring and detecting when activation groups fail so that it can
remove stale remote references from its internal tables.

The activate method
activates the object associated with the activation identifier,
id. If the activator knows the object to be active already
and the force parameter is false, the stub with a
"live" reference is returned immediately to the caller;
otherwise, if the activator does not know that the corresponding
remote object is active or the force parameter is
true, the activator uses the activation descriptor
information (previously registered to obtain the id) to
determine the group (JVM) in which the object should be activated.
If an ActivationInstantiator corresponding to the
object's group already exists, the activator invokes the
activation instantiator's newInstance method,
passing it the id and the object's activation
descriptor.

If the activation instantiator
(group) for the object's group descriptor does not yet exist,
the activator starts a new incarnation of an
ActivationInstantiator executing (by spawning a child
process, for example). When the activator re-creates an
ActivationInstantiator for a group, it must increment
the group's incarnation number. Note that the incarnation
number is zero-based. The activation system uses incarnation
numbers to detect late ActivationSystem.activeGroup
and ActivationMonitor.inactiveGroup calls. The
activation system discards calls with an earlier incarnation number
than the current number for the group.

Note - The activator must communicate
both the activation group's identifier, descriptor, and
incarnation number when it starts up a new activation group. The
activator spawns an activation group in a separate JVM (as a
separate or child process, for example), and therefore must pass
information specifying the information necessary to create the
group via the ActivationGroup.createGroup method. How
the activator sends this information to the spawned process is
unspecified, however, this information could be sent in the form of
marshalled objects to the child process's standard
input.
When the activator receives the
activation group's call back (via the
ActivationSystem.activeGroup method) specifying the
activation group's reference and incarnation number, the
activator can then invoke that activation instantiator's
newInstance method to forward each pending activation
request to the activation instantiator and return the result (a
marshalled remote object reference, a stub) to each
caller.

Note that the activator receives a
MarshalledObject instead of a Remote
object so that the activator does not need to load the code for
that object, or participate in distributed garbage collection for
that object. If the activator kept a strong reference to the remote
object, the activator would then prevent the object from being
garbage collected under the normal distributed garbage collection
mechanism.

The activate method
throws ActivationException if activation fails.
Activation may fail for a variety of reasons: the class could not
be found, the activation group could not be contacted, etc. The
activate method throws
UnknownObjectException if no activation descriptor for
the activation identifier, id, has been previously
registered with this activator. RemoteException is
thrown if the remote call to the activator fails.

7.4.2 The ActivationSystem Interface

The ActivationSystem
provides a means for registering groups and activatable
objects to be activated within those groups. The
ActivationSystem works closely with both the
Activator, which activates objects registered via the
ActivationSystem, and the
ActivationMonitor, which obtains information about
active and inactive objects and inactive groups.

Note - As a security measure, all of the
above methods (registerGroup,
activeGroup, unregisterGroup,
registerObject, unregisterObject, and
shutdown) will throw
java.rmi.AccessException, a subclass of
java.rmi.RemoteException, if called from a client that
does not reside on the same host as the activation system.
The registerObject method
is used to register an activation descriptor, desc, and
obtain an activation identifier for an activatable remote object.
The ActivationSystem creates an
ActivationID (an activation identifier) for the object
specified by the descriptor, desc, and records, in stable
storage, the activation descriptor and its associated identifier
for later use. When the Activator receives an
activate request for a specific identifier, it looks
up the activation descriptor (registered previously) for the
specified identifier and uses that information to activate the
object. If the group referred to in desc is not registered
with this system, then the method throws
UnknownGroupException. If registration fails (e.g.,
database update failure, etc), then the method throws
ActivationException. If the remote call fails, then
RemoteException is thrown.

The unregisterObject
method removes the activation identifier, id, and
associated descriptor previously registered with the
ActivationSystem. After the call completes, the object
can no longer be activated via the object's activation id.
If the object id is unknown (not registered) the method
throws UnknownObjectException. If the unregister
operation fails (e.g., database update failure, etc.), then the
method throws ActivationException. If the remote call
fails, then RemoteException is thrown.

The registerGroup
method registers the activation group specified by the group
descriptor, desc, with the activation system and returns
the ActivationGroupID assigned to that group. An
activation group must be registered with the
ActivationSystem before objects can be registered
within that group. If group registration fails, the method throws
ActivationException. If the remote call fails, then
RemoteException is thrown.

The activeGroup method
is a call back from the ActivationGroup (with the
identifier, id), to inform the activation system that
group is now active and is the
ActivationInstantiator for that JVM. This call is made
internally by the ActivationGroup.createGroup method
to obtain an ActivationMonitor that the group uses to
update the system regarding objects' and the group's status
(i.e., that the group or objects within that group have become
inactive). If the group is not registered, then the method throws
UnknownGroupException. If the group is already active,
then ActivationException is thrown. If the remote call
to the activation system fails, then RemoteException
is thrown.

The unregisterGroup
method removes the activation group with identifier, id,
from the activation system. An activation group makes this call
back to inform the activator that the group should be destroyed. If
this call completes successfully, objects can no longer be
registered or activated within the group. All information of the
group and its associated objects is removed from the system. The
method throws UnknownGroupException if the group is
not registered. If the remote call fails, then
RemoteException is thrown. If the unregister fails,
ActivationException is thrown (e.g., database update
failure, etc.).

The shutdown method
gracefully terminates (asynchronously) the activation system and
all related activation processes (activator, monitors and groups).
All groups spawned by the activation daemon will be destroyed and
the activation daemon will exit. In order to shut down the
activation system daemon, rmid, execute the
command:

rmid -stop [-port num]

This command will shut down the
activation daemon on the specified port (if no port is specified,
the daemon on the default port will be shut down).

7.4.3 The ActivationMonitor Class

An ActivationMonitor is
specific to an ActivationGroup and is obtained when a
group is reported via a call to
ActivationSystem.activeGroup (this is done internally
by the ActivationGroup.createGroup method). An
activation group is responsible for informing its
ActivationMonitor when:

An activation group calls its
monitor's inactiveObject method when an object in
its group becomes inactive (deactivates). An activation group
discovers that an object (that it participated in activating) in
its JVM is no longer active via a call to the activation
group's inactiveObject method.

The inactiveObject call
informs the ActivationMonitor that the remote object
reference it holds for the object with the activation identifier,
id, is no longer valid. The monitor considers the
reference associated with id as a stale reference. Since
the reference is considered stale, a subsequent
activate call for the same activation identifier
results in re-activating the remote object. If the object is not
known to the ActivationMonitor, the method throws
UnknownObjectException. If the remote call fails, then
RemoteException is thrown.

The activeObject call
informs the ActivationMonitor that the object
associated with id is now active. The parameter
obj is the marshalled representation of the object's
stub. An ActivationGroup must inform its monitor if an
object in its group becomes active by other means than being
activated directly by the system (i.e., the object is registered
and "activated" itself). If the object id is not previously
registered, then the method throws
UnknownObjectException. If the remote call fails, then
RemoteException is thrown.

The inactiveGroup call
informs the monitor that the group specified by id and
incarnation is now inactive. The group will be re-created
with a greater incarnation number upon a subsequent request to
activate an object within the group. A group becomes inactive when
all objects in the group report that they are inactive. If either
the group id is not registered or the incarnation number
is smaller than the current incarnation for the group, then the
method throws UnknownGroupException. If the remote
call fails, then RemoteException is thrown.

7.4.4 The
ActivationInstantiator Class

The ActivationInstantiator
is responsible for creating instances of activatable objects. A
concrete subclass of ActivationGroup implements the
newInstance method to handle creating objects within
the group.

The activator calls an
instantiator's newInstance method in order to
re-create in that group an object with the activation identifier,
id, and descriptor, desc. The instantiator is
responsible for:

determining the class for the
object using the descriptor's getClassName
method,

loading the class from the codebase
path obtained from the descriptor (using the
getLocation method),

creating an instance of the class
by invoking the special "activation" constructor of the
object's class that takes two arguments: the object's
ActivationID, and the MarshalledObject
containing object-specific initialization data, and

returning a
MarshalledObject containing the remote object it
created.

An instantiator is also responsible for
reporting when objects it creates or activates are no longer
active, so that it can make the appropriate
inactiveObject call to its
ActivationMonitor (see the
ActivationGroup class for more details).

If object activation fails, then the
newInstance method throws ActivationException. If the
remote call fails, then the method throws
RemoteException.

7.4.5 The
ActivationGroupDesc Class

An activation group descriptor
(ActivationGroupDesc) contains the information
necessary to create or re-create an activation group in which to
activate objects in the same JVM.

Such a descriptor contains:

the group's class name (a class
name of null indicates the default
ActivationGroup implementation),

the group's codebase path (the
location of the group's class), and

a "marshalled" object that
can contain object-specific initialization data.

The group's class must be a concrete
subclass of ActivationGroup. A subclass of
ActivationGroup is created or re-created via the
ActivationGroup.createGroup static method, which
invokes a special constructor that takes two arguments:

The first constructor creates a group
descriptor that uses system default for group implementation and
code location. Properties specify Java application environment
overrides (which will override system properties in the group
implementation's JVM). The command environment can control the
exact command/options used in starting the child JVM, or can be
null to accept rmid's default. This
constructor will create an ActivationGroupDesc with a
null group class name, which indicates the
system's default ActivationGroup implementation.

The second constructor is the same
as the first, but allows the specification of
Properties and CommandEnvironment.

The getClassName method
returns the group's class name (possibly null). A
null group class name indicates the system's
default ActivationGroup implementation.

The getLocation method
returns the codebase path from where the group's class can be
loaded.

7.4.7 The
ActivationGroupID Class

The identifier for a registered
activation group serves several purposes:

it identifies the group uniquely
within the activation system, and

it contains a reference to the
group's activation system so that the group can contact its
activation system when necessary.

The ActivationGroupID is
returned from the call to
ActivationSystem.registerGroup and is used to identify
the group within the activation system. This group identifier is
passed as one of the arguments to the activation group's
special constructor when an activation group is created or
re-created.

The ActivationGroupID
constructor creates a unique group identifier whose
ActivationSystem is system.

The getSystem method
returns the activation system for the group.

The hashCode method
returns a hashcode for the group's identifier. Two group
identifiers that refer to the same remote group will have the same
hash code.

The equals method
compares two group identifiers for content equality. The method
returns true if both of the following conditions are
true: 1) the unique identifiers are equivalent (by content), and 2)
the activation system specified in each refers to the same remote
object.

7.4.8 The
ActivationGroup Class

An ActivationGroup is
responsible for creating new instances of activatable objects in
its group, informing its ActivationMonitor when:

a. its objects become active,

b. its objects become inactive, or

c. the group as a whole becomes inactive.

An ActivationGroup is
initially created in one of several ways:

as a side-effect of creating a
"default" ActivationDesc for an object,
or

by an explicit call to the
ActivationGroup.createGroup method, or

as a side-effect of activating the
first object in a group whose ActivationGroupDesc was
only registered.

Only the activator can
re-create an ActivationGroup. The activator
spawns, as needed, a separate JVM (as a child process, for example)
for each registered activation group and directs activation
requests to the appropriate group. It is implementation specific
how JVMs are spawned. An activation group is created via the
ActivationGroup.createGroup static method. The
createGroup method has two requirements on the group
to be created: 1) the group must be a concrete subclass of
ActivationGroup, and 2) the group must have a
constructor that takes two arguments:

the group's
ActivationGroupID, and

the group's initialization data (in
a MarshalledObject)

When created, the default
implementation of ActivationGroup will set the system
properties to the system properties in force when the
ActivationGroupDesc was created, and will set the
security manager to the java.rmi.RMISecurityManager.
If your application requires some specific properties to be set
when objects are activated in the group, the application should set
the properties before creating any ActivationDescs
(before the default ActivationGroupDesc is created).

The activator calls an activation
group's newInstance method in order to activate an
object with the activation descriptor, desc. The
activation group is responsible for:

determining the class for the
object using the descriptor's getClassName
method,

loading the class from the URL path
obtained from the descriptor (using the getLocation
method),

creating an instance of the class
by invoking the special constructor of the object's class that
takes two arguments: the object's ActivationID,
and a MarshalledObject containing the object's
initialization data, and

returning a serialized version of
the remote object it just created to the activator.

The method throws
ActivationException if the instance for the given
descriptor could not be created.

The group's
inactiveObject method is called indirectly via a call
to the Activatable.inactive method. A remote object
implementation must call Activatable's
inactive method when that object deactivates (the
object deems that it is no longer active). If the object does not
call Activatable.inactive when it deactivates, the
object will never be garbage collected since the group keeps strong
references to the objects it creates.

The group's
inactiveObject method unexports the remote object,
associated with id (only if there are no pending or
executing calls to the remote object) from the RMI runtime so that
the object can no longer receive incoming RMI calls. If the object
currently has pending or executing calls,
inactiveObject returns false and no
action is taken.

If the unexportObject
operation was successful (meaning that the object has no pending or
executing calls), the group informs its
ActivationMonitor (via the monitor's
inactiveObject method) that the remote object is not
currently active so that the remote object will be reactivated by
the activator upon a subsequent activation request. If the
operation was successful, inactiveObject returns
true. The operation may still succeed if the object is
considered active by the ActivationGroup but has
already been unexported.

The inactiveObject
method throws an UnknownObjectException if the
activation group has no knowledge of this object (e.g., the object
was previously reported as inactive, or the object was never
activated via the activation group). If the inactive operation
fails (e.g., if the remote call to the activator or activation
group fails), RemoteException is thrown.

The createGroup method
creates and sets the activation group for the current JVM. The
activation group can only be set if it is not currently set. An
activation group is set using the createGroup method
when the Activator initiates the re-creation of an
activation group in order to carry out incoming
activate requests. A group must first register a group
descriptor with the ActivationSystem before it can be
created via this method (passing it the ActivationID
obtained from previous registration).

The group specified by the
ActivationGroupDesc, desc, must be a concrete
subclass of ActivationGroup and have a public
constructor that takes two arguments; the
ActivationGroupID for the group and a
MarshalledObject containing the group's
initialization data (obtained from its
ActivationGroupDesc). If the
ActivationGroupDesc.getClassName method returns
null, the system's default group implementation is
used. Note: if your application creates its own custom activation
group, the group must set a security manager in the constructor, or
objects cannot be activated in the group.

After the group is created, the
ActivationSystem is informed that the group is active
by calling the activeGroup method, which returns the
ActivationMonitor for the group. The application need
not call activeGroup independently since that callback
is taken care of by the createGroup method.

Once a group is created, subsequent
calls to the currentGroupID method will return the
identifier for this group until the group becomes inactive, at
which point the currentGroupID method will return
null.

The parameter incarnation
indicates the current group incarnation, i.e., the number of times
the group has been activated. The incarnation number is used as a
parameter to the activeGroup method, once the group
has been successfully created. The incarnation number is
zero-based. If the group already exists, or if an error occurs
during group creation, the createGroup method throws
ActivationException.

The setSystem method
sets the ActivationSystem, system, for the
JVM. The activation system can only be set if no group is currently
active. If the activation system is not set via an explicit call to
setSystem, then the getSystem method will
attempt to obtain a reference to the ActivationSystem
by looking up the name
java.rmi.activation.ActivationSystem in the
Activator's registry. By default, the port number used to look
up the activation system is defined by
ActivationSystem.SYSTEM_PORT. This port can be overridden
by setting the property java.rmi.activation.port. If the
activation system is already set when setSystem is
called, the method throws ActivationException.

The getSystem method
returns the activation system for the JVM. The activation system
may be set by the setSystem method (described
above).

The activeObject method
is a protected method used by subclasses to make the
activeObject call back to the group's monitor to
inform the monitor that the remote object with the specified
activation id and whose stub is contained in mobj
is now active. The call is simply forwarded to the group's
ActivationMonitor.

The inactiveGroup
method is a protected method used by subclasses to inform the
group's monitor that the group has become inactive. A subclass
makes this call when each object the group participated in
activating in the JVM has become inactive.

7.4.9 The MarshalledObject Class

A MarshalledObject is a
container for an object that allows that object to be passed as a
parameter in an RMI call, but postpones deserializing the object at
the receiver until the application explicitly requests the object
(via a call to the container object). The Serializable
object contained in the MarshalledObject is serialized
and deserialized (when requested) with the same semantics as
parameters passed in RMI calls, which means that any remote object
in the MarshalledObject is represented by a serialized
instance of its stub. The object contained by the
MarshalledObject may be a remote object, a non-remote
object, or an entire graph of remote and non-remote objects.

When an object is placed inside the
MarshalledObject wrapper, the serialized form of the
object is annotated with the codebase URL (where the class can be
loaded); likewise, when the contained object is retrieved from its
MarshalledObject wrapper, if the code for the object
is not available locally, the URL (annotated during serialization)
is used to locate and load the bytecodes for the object's
class.

MarshalledObject's
constructor takes a serializable object, obj, as its
single argument and holds the marshalled representation of the
object in a byte stream. The marshalled representation of the
object preserves the semantics of objects that are passed in RMI
calls:

each class in the stream is
annotated with its codebase URL so that when the object is
reconstructed (by a call to the get method), the
bytecodes for each class can be located and loaded, and

remote objects are replaced with
their proxy stubs.

When an instance of the class
MarshalledObject is written to a
java.io.ObjectOutputStream, the contained object's
marshalled form (created during construction) is written to the
stream; thus, only the byte stream is serialized.

When a MarshalledObject
is read from a java.io.ObjectInputStream, the
contained object is not deserialized into a concrete object; the
object remains in its marshalled representation until the
marshalled object's get method is called.

The get method always
reconstructs a new copy of the contained object from its marshalled
form. The internal representation is deserialized with the
semantics used for unmarshalling parameters for RMI calls. So, the
deserialization of the object's representation loads class code
(if not available locally) using the URL annotation embedded in the
serialized stream for the object.

The hashCode of the
marshalled representation of the object is the same as the object
passed to the constructor. The equals method will
return true if the marshalled representation of the objects being
compared are equivalent. The comparison that equals uses ignores a
class's codebase annotation, meaning that two objects are
equivalent if they have the same serialized representation
except for the codebase of each class in the serialized
representation.