If you are new to the Apache River release or doing day-to-day development, you probably don't need to use the activatable mode of the contributed implementations. The non-activatable modes are considerably simpler to deal with and understand. The activatable mode may be necessary or helpful in certain deployment scenarios or when you need to test in an environment similar to what you will deploy into and are using the activatable mode in deployment.
A Java RMI activation system daemon (activation daemon) is a process that continually runs on a system to ensure that activatable services are available when they are needed. Once an activation daemon is running, its remote methods can be invoked to register information on how to start activatable services. This registration process returns a remote reference to the service, but the service itself is not yet running. The remote reference to the service can be made available for clients to use directly, or via a smart proxy. Whether embedded in a proxy or not, the reference is generally made available by means of a River lookup service, though any mechanism that allows for the transfer of serializable objects can also be used.
While the service's reference appears to clients to be a normal remote
reference, it acts a bit differently. This remote reference contains the
information necessary to contact both the activation daemon on the
service's host and the service itself. When a client invokes a
method on this remote reference object, the reference object first tries to
contact the service directly; if this attempt fails, it contacts the
activation daemon. If necessary, the activation daemon (re)starts the
service in a new VM and passes the contact information for the new VM back
to the remote reference. The remote reference then tries to contact the
service using this new contact information. If this second attempt fails,
or if the remote reference cannot contact the activation daemon, then the
remote reference throws a RemoteException
.
When a service is registered with the activation daemon, the registration
is logged to disk. When the activation daemon is restarted after a crash or
other outage it will read the log and the service will again be
available. If, at some point, the service decides it should no longer
exist, it must explicitly unregister with the activation daemon; simply
calling System.exit
will not keep it from being restarted by
the activation daemon.
VM Independence
The service now has an existence that is independent of any particular
VM. As long as the activation daemon is reachable, the service is reachable
and exists even if the service itself is not currently running inside a
VM. If the activation daemon is not running but its logs are intact,
restarting the activation daemon will make the service reachable again. In
a very real sense, the service exists (although it may be inaccessible) as
long as the activation daemon's logs and the service's logs exist. When you
kill an activation daemon and delete its logs, you are really destroying
all the services that have registered with it.
The key to this independence is the remote references that activation creates for the service. These are persistent references; that is, they keep on working after the original VM in which the service was hosted goes away. With Java RMI/JRMP (the Java RMI implementation included with the Java Development Kit) activation is the only supported way to get persistent references. With Jini extensible method invocation (Jini ERI) there are two ways to create persistent references. One way is to use activation. The second way is to create references with fixed ports and object IDs. The package documentation for each of the contributed service implementations includes example configurations demonstrating how this can be done.
Multiple Service Dependence
In general, more than one service will be registered with a given
activation daemon. Thus, while you can destroy a service by killing the
activation daemon and deleting its logs, you will most likely destroy
quite a few other services in the process.
A better approach is to tell the service that you no longer need it and
that it should destroy itself. The administration interfaces of all the
service implementations in the Apache River release support the
org.apache.river.admin.DestroyAdmin
interface. Invoking the destroy
method on the admin of an activatable service will cause the service to be
unregistered with the activation daemon, the service's logs to be
destroyed, and all the threads the service has started to be stopped (which
means if there are no other non-daemon threads, the VM will exit). Invoking
destroy
on only a single service will leave the activation
daemon, and any other services registered with it, intact and
available. When the example
service browser that ships with the Apache River release is started with the
folderView
configuration entry set to true
(which
is the default), it can be used to destroy services that implement
DestroyAdmin
.
Service Persistence
Another implication of using activatable services is that, in the normal
course of events, you don't need to individually restart the services after
restarting the activation daemon; the activation daemon will do it for
you. If the activation daemon's log is still intact, it will
automatically restart the services as necessary. Each time you use the
service starter to start an activatable service, you are not restarting an
existing service instance, but creating a completely new service instance
with its own identity and state.
For example, if you were to invoke the service starter using "java
-jar start.jar start-activatable-reggie.config
" to start an
activatable Reggie server, then kill the activation daemon, restart the
activation daemon, and invoke "java -jar start.jar
start-activatable-reggie.config
" again, you will end up with
two Reggie services, not one. If you keep on doing this you will end
up with a very large number of Reggie services, the activation daemon will
take a long time to restart, and your system will slow to a crawl. Also, if
you have not given them separate log directories, the Reggie services will
start interfering with each other. You should only invoke "java -jar
start.jar start-activatable-reggie.config
" more than once if you
want more than one Reggie running on the machine in question, or if the
first instance of Reggie has been destroyed (as opposed to having only
crashed).
The VM You Start and the Service VM are Separate
When you invoke the service starter to create an activatable service
instance, a VM is created for the service starter to do its work in;
generally this is done with a command line of the form java -jar
start.jar ...
. We refer to this VM as the setup VM. The
service starter makes some remote calls to the activation daemon to
register the new service. This will cause the activation daemon to spawn a
new VM for the service to run in. We refer to this VM as the server
VM. This is very different from what happens when the service starter
is asked to create a non-activatable (transient or persistent) service, in
which case there is only one VM.
Unless the service starter has been asked to host non-activatable services in addition to creating new activatable services, the setup VM will exit once it has registered the new activatable service(s) with the activation daemon. This is normal. If the setup VM exits cleanly (e.g. no exceptions are printed out) the new service has been created and (if properly configured) is available for use.
Because the server VM is a child of the activation daemon, anything sent to
the service's System.out
or System.err
will appear
not in the setup VM's console session, but in the activation daemon's
console session.
Lastly, because the activation daemon is starting the server VM, you have
less direct control over how it is started than the setup VM. For example
if you wanted to have the service run in a VM with the -server
command line switch set, adding -server
to the command line
used for the setup VM will not help. How the service VM is spawned is
controlled by the org.apache.river.start.SharedActivationGroupDescriptor
that was responsible for creating the activation group to which
that service has been assigned.
Service Starter Needs More Information
Service starter determines what needs to be done by getting an array of org.apache.river.start.ServiceDescriptor
s
using the serviceDescriptors
configuration entry. Creating a
single non-activatable service requires only a single instance of org.apache.river.start.NonActivatableServiceDescriptor
,
while creating instances of activatable services is a bit more involved
and has more options.
Each activatable service needs to be assigned to an activation
group. Activation groups are created by placing instances of
SharedActivationGroupDescriptor
in the
serviceDescriptors
array. As mentioned above, the
SharedActivationGroupDescriptor
will control the details of
how the server VM is spawned.
Once you have an activation group, one or more activatable services can be
assigned to it. Activatable services are created by placing instances of org.apache.river.start.SharedActivatableServiceDescriptor
in the serviceDescriptors
array, one instance per activatable
service to be created.
There is one additional wrinkle to consider. Because of the way
SharedActivatableServiceDescriptor
s are associated with
activation groups, a group can be created by one service starter
invocation, and separate service starter invocations can be used to add
activatable services to that group. For example you could use one service
starter invocation to create a group and put 30 services in it, or you
could invoke the service starter to just create a group, and then run the
service starter again to add one or more services. In either case you could
come back three weeks later and add more services to an existing group.
Tutorials on how to write an activatable service.
There are two activation daemon implementations available. rmid
ships with the Java Development Kit:
rmid
on Microsoft Windows
rmid
with the Solaris(TM) Operating System
and/or Linux
The second is phoenix, which is
part of the release. Phoenix has better support for Jini ERI, is
configurable, and supports net.jini.security
, making it
suitable for a much broader range of deployments than rmid
.
Because activation daemons are capable of spawning arbitrary subprocesses, there are some security issues to consider.