<?xml version='1.0'?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
               "http://docbook.org/xml/4.2/docbookx.dtd"
	       [
	       <!ENTITY copyright SYSTEM "copyright.xml">
	       ]>

<chapter label="Activation" id="23">
  <title>
    Activation
  </title>

  <tocchap>
    <tocentry>
      Activation
    </tocentry>
    <toclevel1>
      <tocentry linkend="Introduction">
	<ulink url="#Introduction">Introduction</ulink>
      </tocentry>
    </toclevel1>
    <toclevel1>
      <tocentry>
	<ulink url="#Phoenix">Phoenix</ulink>
      </tocentry>
    </toclevel1>
    <toclevel1>
      <tocentry>
	<ulink url="#A Service using Activation">A Service using
	  Activation</ulink>
      </tocentry>
      <toclevel2>
	<tocentry>
	  <ulink url="#Service">Service</ulink>
	</tocentry>
      </toclevel2>
      <toclevel2>
	<tocentry>
	  <ulink url="#Server">Server</ulink>
	</tocentry>
      </toclevel2>
      <toclevel2>
	<tocentry>
	  <ulink url="#Running the Service">Running the
	    Service</ulink>
	</tocentry>
      </toclevel2>
    </toclevel1>
<!--
	<tocentry>
	  <ulink url="#Security">Security</ulink>
	</tocentry>
-->
    <toclevel1>
      <tocentry>
	<ulink url="#Non-lazy Services">Non-lazy Services</ulink>
      </tocentry>
    </toclevel1>
    <toclevel1>
	<tocentry>
	  <ulink url="#Maintaining State">Maintaining State</ulink>
	</tocentry>
    </toclevel1>
    <toclevel1>
      <tocentry>
	<ulink url="#LeaseRenewalService">LeaseRenewalService</ulink>
      </tocentry>
      <toclevel2>
	<tocentry>
	  <ulink url="#The Norm Service">The Norm Service</ulink>
	</tocentry>
      </toclevel2>
      <toclevel2>
	<tocentry>
	  <ulink url="#Using the LeaseRenewalService">Using the
	    LeaseRenewalService</ulink>
	</tocentry>
      </toclevel2>
    </toclevel1>
    <toclevel1>
      <tocentry>
	<ulink
	  url="#LookupDiscoveryService">LookupDiscoveryService</ulink>
      </tocentry>
      <toclevel2>
	<tocentry>
	  <ulink url="#Fiddler">The Fiddler Service</ulink>
	</tocentry>
      </toclevel2>
      <toclevel2>
	<tocentry>
	  <ulink url="#Using the LookupDiscoveryService">Using the
	    LookupDiscoveryService</ulink>
	</tocentry>
      </toclevel2>
    </toclevel1>
    <toclevel1>
      <tocentry>
	<ulink url="#Summary">Summary</ulink>
      </tocentry>
    </toclevel1>
  </tocchap>
 
  
  <abstract>
    <para>
      
    </para>
  </abstract>
  
  <sect1>
    <title id="Introduction">
      Introduction
    </title>
    
    
    <note id="changed">
      <para>
	Many of the examples in earlier chapters use RMI/Jeri proxies
	for services. These services live within a server whose
	principal task is to keep the service alive and registered
	with lookup services. If the server fails to renew leases then
	lookup services will eventually discard the proxy; if the
	server fails to keep itself and its service alive then the
	service will not be available when a client wants to use it.
      </para>
    </note>
    
    
    <note id="changed">
      <para>
	This results in a server and a service which most of the time
	will be idle, probably swapped out to disk but still using
	virtual memory. Java memory requirements on the server side
	can be enormous From JDK 1.2, there is an extension to RMI
	called <emphasis>activation</emphasis> which allows an idle
	object to be "dormant", and be brought to life when needed. In
	this way, it does not occupy virtual memory while idle. Of
	course, <emphasis>another</emphasis> process needs to be alive
	to restore such objects, and RMI supplies a daemon
	<command>rmid</command> (in Jini 1.2) and
	<command>phoenix</command> (in Jini 2.0) to manage this. In
	effect, <command>rmid/phoenix</command> acts as another
	virtual memory manager as it stores information about dormant
	Java objects in its own files and restores them from there as
	needed.
      </para>
    </note>
    
    
    
    <note id="changed">
      <para>
	There are serious limitations to <command>rmid</command> and
	<command>phoenix</command>: they are Java program themselves
	and when running also uses enormous amounts of memory! So it
	only makes sense to use this technique when you expect to be
	running a number of largely idle services on the same machine.
	When a service is brought to life, or
	<emphasis>activated</emphasis>, a new JVM may be started to
	run the object. This again increases memory use.
      </para>
    </note>
    
    
    
    <note id="changed">
      <para>
	If memory use was the only concern, then there are a variety
	of other systems such as <command>echidna</command> which run
	multiple applications within a single JVM. These may be
	adequate to solve memory issues. However, RMI Activation is
	also designed to work with distributed objects, and allows
	JVM's to hold remote references to objects which are no longer
	active. Instead of throwing a remote exception on trying to
	access these objects, the Activation system tries to resurrect
	the object using <command>rmid</command> or
	<command>phoenix</command> to give a valid (and new)
	reference. Of course, if it fails to do this, it will throw an
	exception anyway.
      </para>
    </note>
        
    <note id="changed">
      <para>
	The standard RMI activation system is supported by Jini 2.0,
	in the same way as it supports JRMP. But with the advent of
	Jeri, Jini 2.0 has a new version of activation with a new
	activation server, <command>phoenix</command>.
      </para>
    </note>
    
  </sect1>
  
  <sect1>
    <title id="Phoenix">
      Phoenix
    </title>
    
    <para>
      Phoenix replaces <command>rmid</command> in Jini 2.0. It comes
      in a variety of versions, depending on the protocol it supports.
      So if the services use Jeri, then <command>phoenix</command>
      should be configured to use Jeri also. Similarly, if the
      services use JRMP then so should <command>phoenix</command>.
    </para>
    
    <para>
      Phoenix can be started by using the <classname>ServiceStarter</classname> or by
      shell scripts/batch files. Example scripts are given in the Jini
      distribution under the 
      <filename>source/vob/jive/src/com/sun/jini/example/hello/scripts/</filename>
      directory. For example, here is the shell script 
      <command>jeri-phoenix.sh</command>
      which starts the Jeri version of Phoenix under Unix
      <programlisting>
host=`hostname`

java -Djava.security.manager=                                           \
     -Djava.security.policy=config/phoenix.policy                       \
     -Djava.rmi.server.codebase=http://$host:8080/phoenix-dl.jar        \
     -DserverHost=$host                                                 \
     -jar lib/phoenix.jar                                               \
     config/jeri-phoenix.config
      </programlisting>

      and here is the batch file <command>jrmp-phoenix.bat</command> 
      which starts the Jeri version of Phoenix under Windows
      <programlisting>
java -Djava.security.manager= ^
     -Djava.security.policy=config\phoenix.policy ^
     -Djava.rmi.server.codebase=http://%computername%:8080/phoenix-dl.jar ^
     -DserverHost=%computername% ^
     -jar lib\phoenix.jar ^
     config\jrmp-phoenix.config
      </programlisting>
    </para>
    
    <para>
      Each script file references a configuration script. A typical script such
      as <command>config/jeri-phoenix.config</command> contains
      <programlisting>
com.sun.jini.phoenix {

    persistenceDirectory = "lib${/}phoenix-log";
    groupConfig = new String[] { "config${/}jeri-phoenix-group.config" };
}
      </programlisting>
      which states the directory to store the activation log files and also a
      group configuration file such as <filename>jeri-phoenix-group.config</filename>
      <programlisting>
import com.sun.jini.phoenix.AccessILFactory;
import net.jini.jeri.BasicJeriExporter;
import net.jini.jeri.tcp.TcpServerEndpoint;

com.sun.jini.phoenix {

    instantiatorExporter =
        new BasicJeriExporter(TcpServerEndpoint.getInstance(0),
                              new AccessILFactory());

}
      </programlisting>
      This file defines the protocol that will be used by Phoenix- here, Jeri.
    </para>
    
    <para>
      There is a little trap in running Phoenix: it will create a new virtual
      machine for each different group. This new virtual machine will require
      several files such as 
      <filename>phoenix-init.jar</filename> jar file in its classpath.
      So it is not enough to specify <filename>phoenix.jar</filename> for 
      <command>phoenix</command> - the <filename>phoenix-init.jar</filename> file
      must be in the classpath for any virtual machines created by Phoenix.
      This must be done for each activatable service. An alternative to
      explicitly setting the  classpath is to copy the file
      <filename>phoenix-init.jar</filename> to the Java jre lib directory
      (as you probably did with <filename>jsk-policy.jar</filename>).
      But this is not really recommended.
      If the clsaspath is not set up, 
      then when Phoenix starts a new JVM, you will see errors such as
      <programlisting>
Group-01: class not found ActivationInitGroup
      </programlisting>
    </para>

    <para>
      The Sun documentation recommends including <filename>sharedvm.jar</filename>
      in the classpath, and the directory for this jar file should also
      contain <filename>phoenix-init.jar</filename> and
      <filename>jsk-platform.jar</filename>.
    </para>
  </sect1>
  
  <sect1>
    <title id="A Service using Activation">
      A Service using Activation
    </title>
    
    <para>
      The major concepts in Activation are the activatable object
      itself (which extends
      <classname>java.rmi.activation.Activatable</classname>) and the
      environment in which it runs, an
      <classname>ActivationGroup</classname>. A JVM may have an
      activation group associated with it. If an object needs to be
      activated and there is already a JVM running its group then it
      is restarted within that JVM. Otherwise, a new JVM is started.
      An activation group may hold a number of co-operating objects.
    </para>
    
    <sect2>
      <title id="Service">
	Service
      </title>
      
      <note id="changed">
	<para>
	  Making an object into an activable object requires  registering the
	  object with the activation system by exporting it, and by
	  using a special two-argument constructor
	  which will be called when the object needs to be reconstructed.
	  The constructor looks like:
	  <programlisting>
public ActivatableImpl(ActivationID id, MarshalledObject data)
    throws RemoteException {
    ...
}
	  </programlisting>
	  (The use of the marshalled data is discussed later).
	</para>
      </note>

      <note id="new">
	<para>
	  There is an important conceptual change from non-activatable
	  services. In a non-activatable service, the
	  <emphasis>server</emphasis> is able to create the
	  <emphasis>service</emphasis>. In an activation system, the
	  original server could have terminated, and will not be
	  available to start the service. Instead, the activation server is
	  responsible for that. But the service still has to be
	  exported, and it can't rely on the activation server to do that (for
	  example, it would have no knowledge of
	  the protocol such as Jeri/JRMP/IIOP). So the service has to
	  export itself. That is, within the constructor the service
	  must find an exporter and export itself. This is a change
	  from "standard" activation as used in Jini 1.2: there, many
	  things were hidden from the programmer and it was not neccessary
	  to pay attention to this.
	</para>
      </note>

      <note id="new">
	<para>
	  That in turn raises another problem: in a non-activatable service,
	  the server creates the service, gets a proxy by exporting the service
	  and then does things like register the proxy with lookup services.
	  But if the export operation is buried within the 
	  <emphasis>service</emphasis> constructor, then a
	  <emphasis>server</emphasis> cannot readily get access to it.
	  This is the role of the <classname>ProxyAccessor</classname>
	  interface: it supplies a method that a server can call on the service
	  to give the proxy. Unless the service can do everything itself,
	  it will usually need to implement this interface.
	  (An exception to this occurs when the service is its own proxy:
	  it just needs to be <classname>Serialisable</classname> in that
	  case.)
	</para>

	<para>
	  With these in place, the file classifier becomes
	  <programlisting>
	    <?program "src/activation/FileClassifierImpl.java"?>
	  </programlisting>

	  This listing makes explicit use of an exporter. Later we shall consider
	  how this could be done using a configuration.
	</para>
      </note>
    </sect2>

    <sect2>
      <title id="Server">
	Server
      </title>

      <note id="new">
	<para>
	  The server doesn't actually start the service - that is the task of
	  a process like <command>phoenix</command>. What the server has to do is
	  setup the parameters for the service so that <command>phoenix</command>
	  will know how to handle it. These may include
	  <orderedlist>
	    <listitem>
	      <para>
		Which activation group the service will belong to
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		The security policy to run services in a particular activation group
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		The classpath for <command>phoenix</command> to run the service
		in a new Java virtual machine. Note that this classpath cannot be
		one that is relative to the <emphasis>server</emphasis>, since it
		will be used by <command>phoenix</command>. 
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		The codebase for the client to find the service
		(needed if the service registers itself with lookup
		services)
	      </para>
	    </listitem>
	  </orderedlist>
	  A service is run within an activation group.
	  When a group is run in a new virtual machine, it may need explicit
	  command line options (such as setting the classpath or the stack size)
	  and properties (such as security policy). Of course, properties can
	  be set as command line arguments too, but Java allows them to be set
	  separately. For example, the command line arguments can be set by
	  <programlisting>
String[] options = {"-classpath", 
	            "activation.FileClassifierServer.jar"};
CommandEnvironment commEnv =
	            new CommandEnvironment(null, options);
	  </programlisting>
	  The group parameters are set using an 
	  <classname>ActivationGroupDesc</classname> which takes both a
	  <classname>Properties</classname> list and a 
	  <classname>CommandEnvironment</classname>
	  <programlisting>
String[] options = {"-classpath", 
	            "activation.FileClassifierServer.jar"};
ActivationGroupDesc.CommandEnvironment commEnv =
	    new CommandEnvironment(null, options);
Properties props = new Properties();
props.put("java.security.policy",
	  SECURITY_POLICY_FILE);
props.put("java.rmi.server.codebase", 
	  "http://192.168.1.13/classes/activation.FileClassifierServer-dl.jar");
ActivationGroupDesc group = new ActivationGroupDesc(props, commEnv);
</programlisting>
	  <emphasis>Note: although the classpath shown only references
	    the classes required for the server, in practise you may need to add in
	    more. For example, <command>phoenix</command> requires
	    <filename>phoenix-init.jar</filename> and there may be other Jini
	    class files required too. The easiest way to work out what is required is
	    run the server and observe what <command>phoenix</command>
	    complains about. Alternatively, include 
	    <filename>sharedvm.jar</filename> which points to all likely jar
	    files that may be required by Sun's tools.
	  </emphasis> 
	</para>
      </note>     

      <note id="new">
	<para>
	The next steps are to register the group and get a group ID from that.
	Then an activation description for the service is constructed. This includes
	the group ID and the name of the service's class file. (Two other
	parameters are discussed later.) This service can then be registered
	with <command>phoenix</command>. At this point, the service is with
	<filename>phoenix</filename>, but has not been initialised. So its
	constructor has not been called, and there is no proxy for it. This
	means it cannot yet be registered with a lookup service and cannot yet
	be found by any client. How then can we force it to be constructed?
	At this point the server has an activation ID for the service from
	the registration. It uses this to ask <command>phoenix</command> to
	activate the service by the <code>activate()</code> method.
	The code for this looks like
	<programlisting>
ActivationGroupDesc group = new ActivationGroupDesc(props, commEnv);
ActivationGroupID groupID  = actSys.registerGroup(group);

ActivationGroup.createGroup(groupID, group, 0);
String codebase = "...";
MarshalledObject data = null;
ActivationDesc desc = null;
desc = new ActivationDesc(groupID,
                          "activation.FileClassifierImpl",
                           codebase, data, true);
ActivationID aid =  actSys.registerObject(desc);
Remote stub = (Remote) aid.activate(true);
	</programlisting>
	</para>
      </note>

      <para>
	The server now has a proxy that it can register with lookup services.
	The server can now terminate, since any calls on the service will be
	handled by <command>phoenix</command>, which will construct the
	service whenever a call to that service is made by a client.
	(We shall address later how the registration with lookup services
	is kept alive - if this server terminates then it cannot do any
	lease renewals.)
      </para>

<!--
      <para>
	The server needs to create an activation group for the objects
	to run in. The main issue in this is to set a security policy
	file. There are two security policies in activatable objects:
	the policy used to <emphasis>create</emphasis> the server and
	export the service, and the policy used to
	<emphasis>run</emphasis> the service. The activation group
	sets a policy file for <emphasis>running</emphasis> methods of
	the service object. The policy file for the server is set
	using the normal <command>-Djava.security.policy=...</command>
	argument to starting the server. After setting various
	parameters, the activation group is set for the JVM by
	<code>ActivationGroup.createGroup()</code>.
      </para>
      
      <note id="changed">
	<para>
	  Nonactivatable remote objects are created in the normal way
	  using a constructor that is called by the server.
	  Activatable objects are not constructed in the server but
	  are instead registered with <command>phoenix</command>,
	  which will look after construction on an as-needed basis.
	  <command>rmid</command> needs to know the class name and the
	  location of the class files. These are wrapped up in an
	  <classname>ActivationDesc</classname>, and registered with
	  <command>phoenix</command> by
	  <code>Activatable.register()</code>. This returns an RMI
	  stub object that can be registered with lookup services
	  using the <code>ServiceRegistrar.register()</code> methods.
	  This is also a little different to subclasses of
	  <classname>UnicastRemoteObject</classname> which passes an
	  object which is converted to a stub by the RMI runtime. In
	  point form,
	  <orderedlist>
	    <listitem> <para>
		A service creates a subclass of
		<classname>UnicastRemoteObject</classname> using its
		constructor
	      </para>
	    </listitem>
	    <listitem> <para>
		A subclass of <classname>Activatable</classname> is
		created by <command>rmid</command> using a special
		constructor
	      </para> </listitem>
	    <listitem> <para>
		For an <classname>UnicastRemoteObject</classname>
		object, the server needs to know the class files for
		the class in its classpath, the client needs to know
		the class files for the stub from an HTTP server
	      </para> </listitem>
	    <listitem> <para>
		For an <classname>Activatable</classname> object,
		<command>rmid</command> needs to know the class files
		from an HTTP server, the server must be able to find
		the stub files from its classpath and the client must
		be able to get the stub files from an HTTP server
	      </para> </listitem>
	    <listitem> <para>
		A server hands a
		<classname>UnicastRemoteObject</classname> object to
		the <code>ServiceRegistrar.register()</code>. This is
		converted to the stub by the RMI runtime
	      </para> </listitem>
	    <listitem> <para>
		A server gets a stub for an
		<classname>Activatable</classname> object from
		<code>Activatable.register()</code>. This stub is
		given directly to
		<code>ServiceRegistrar.register()</code>
	      </para> </listitem>
	  </orderedlist>
	</para>
      </note>

      <para>
	The changes for servers from the unicast remote objects are
	<orderedlist>
	  <listitem> <para>
	      An activation group has to be created with a security
	      policy file
	    </para> </listitem>
	  <listitem> <para>
	      The service is not created explicitly but instead
	      registered with <command>rmid</command>
	    </para> </listitem>
	  <listitem> <para>
	      The return object from this registration is a stub that
	      can be registered with lookup services
	    </para> </listitem>
	  <listitem> <para>
	      Leasing vanishes: the server just exits. The service
	      will just expire after a while. Oh well...see the later
	      section on lease renewal services.
	    </para> 
	  </listitem>
	</orderedlist>
      </para>
-->

      <para>
	The file classifier server which uses an activatable service is
	<programlisting>
	  <?program "src/activation/FileClassifierServer.java"?>
	</programlisting>
      </para>
    </sect2>
    
    <sect2>
      <title id="Running the Service">
	Running the Service
      </title>

      <note id="changed">
	<para>
	  The service and the server must be compiled as usual.
	  Nonactivatable services just require classes for the client
	  and for the server. For activatable services it is more
	  complex: classes are required for the client, for the
	  startup server and for <command>phoenix</command>
	  <orderedlist>
	    <listitem>
	      <para>
		The classes that are required by the client must be
		copied to an http server. In this case, it is only the
		class file
		<filename>rmi/RemoteFileClassifier.class</filename>.
		That is, if a protocol such as Jeri is used with stub
		generation at runtime. If JRMP was used, the
		<command>rmic</command> compiler would need to be run on
		<filename>activation/FileClassifierImpl.class</filename> 
		and the resultant stub would also need to be copied to
		the http server
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		The classes needed by the startup server are the file
		classifier server and the classes it needs. 
		This gets a bit tricky. The server doesn't actually
		create the service at any time, so it doesn't need the
		class file for <classname>FileClassifierImpl</classname>.
		But when it activates the service, <command>phoenix</command>
		will create the service and return a proxy for it. This
		proxy will implement <classname>RemoteFileClassifier</classname>.
		So the server will need the class files to support a
		<classname>RemoteFileClassifier</classname> even though it
		doesn't explicitly create one. The files could be either in
		the server's classpath, or in its codebase. This server uses
		the codebase as information in the proxy when it registers
		the service with a lookup service, and so we wouldn't want to
		put extra stuff in there for downloading to a client.
		Instead, the class files may be better off in the server's classpath
		(<emphasis>Hmmm, I'm not completely happy with that - I wonder if
		there is a better way...)</emphasis>
		<orderedlist>
		  <listitem>
		    <para>
		      <code>common/MIMEType.class</code>
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      <code>common/FileClassifier.class</code>
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      <code>rmi/RemoteFileClassifier.class</code>
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      <code>activation/FileClassifierServer.class</code>
		    </para>
		  </listitem>
		</orderedlist>
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		Finally, the classes needed by
		<command>phoenix</command> are
		<code>FileClassifierImpl</code> and its dependencies,
		but not the startup server
		<orderedlist>
		  <listitem>
		    <para>
		      <code>common/MIMEType.class</code>
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      <code>common/FileClassifier.class</code>
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      <code>rmi/RemoteFileClassifier.class</code>
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      <code>activation/FileClassifierImpl.class</code>
		    </para>
		  </listitem>
		</orderedlist>
	      </para>
	    </listitem>
	  </orderedlist> 

	  <!--	  The files to create and in addition
	  an RMI stub object must be created for the service backend
	  using <command>rmic</command> (in JDK 1.2, at least). The
	  class files for the stub must be copied to somewhere that an
	  HTTP server can deliver them to clients. This is the same as
	  for any other RMI stubs. There is an extra step that must be
	  performed for Activatable objects: the activation server
	  <command>rmid</command> must be able to reconstruct a copy
	  of the service <emphasis>backend</emphasis> (the client must
	  be able to reconstruct a copy of the services's
	  <emphasis>stub</emphasis>). This means that
	  <command>rmid</command> must have access to the class files
	  of the service backend, either from an HTTP server or from
	  the file system. In the example, the <code>codebase</code>
	  property in the <classname>ActivationDesc</classname> is set
	  to an HTTP url, so the class files for the service backend
	  must be accessible to an HTTP server. Note that
	  <command>rmid</command> does <emphasis>not</emphasis> get
	  the class files for a service backend from the
	  <code>CLASSPATH</code>, but from the codebase of the
	  service. The HTTP server need not be on the same machine as
	  the service backend. -->
	</para>
      </note>

      <note id="changed">
      <para>
	Before starting the service provider, a
	<command>phoenix</command> process must be set running on the
	<emphasis>same</emphasis> machine as the service provider. An
	HTTP server must be running on a machine as specified by the
	<code>codebase</code> property on the service. The service
	provider can then be started. This will register the service
	with <command>phoenix</command>, and will copy a proxy object up
	to any lookup services that are found. The server can then
	terminate (as mentioned earlier, this will cause the service's
	lease to expire, but techniques to handle this are described
	later).
      </para>
      </note>

      <note id="changed">
	<para>
	In summary, there are typically three processes involved in
	  getting an activatable service running
	<orderedlist>
	    <listitem> <para>
		The service provider, which specifies information
		about the service to <command>phoenix</command>
	      </para> 
	    </listitem>
	    <listitem> 
	      <para>
		<command>phoenix</command>, which must be running on
		the same machine as the service provider, and must be
		started before the service provider. Igt creates the
		service on demand
	      </para> 
	    </listitem>
	    <listitem> 
	      <para>
		An HTTP server, which can be on a different machine,
		and is pointed to by the codebase
	      </para> </listitem>
	</orderedlist>
	</para>
      </note>

      <note id="changed">
	<para>
	  While the service remains registered with lookup services,
	  clients can download its proxy. The service will be created
	  on demand by <command>phoenix</command>. You only need to run
	  the server <emphasis>once</emphasis>, since
	  <command>phoenix</command> keeps information about the service
	  in it own log files.
	</para>
	</note>

      <note id="new">
      <para>
	An Ant file to build, deploy and run the service (but not
	<code>phoenix</code>) is 
	<filename>activation.FileClassifierServer.xml</filename>
	  <programlisting>
	    <?antFile "antBuildFiles/activation.FileClassifierServer.xml"?>
	  </programlisting>
      </para>
      </note>
    </sect2>

<!--
    <sect2>
      <title id="Security">
	Security
      </title>

      <para>
	Note that the JVM for the service will be created by
	<command>rmid</command>, and will be running in the same
	environment as <command>rmid</command>. In particular, such
	things as the current directory for the service will be the
	same as for <command>rmid</command>, not from where the server
	ran. Similarly, the user id for the service will be the user
	id of <command>rmid</command>. This is a potential security
	problem in multi-user systems. For example, any user on a Unix
	system could write a service which attempts to read the shadow
	password file on the system, as an activatable service. Once
	registered with <command>rmid</command>, this same user could
	write a client that calls the appropriate methods on the
	service. If <command>rmid</command> is running in privileged
	mode, owned by the superuser of the system, then the service
	will run in that same mode and will happily read any file in
	the entire file system! For safety, <command>rmid</command>
	should probably be run using the user id <code>nobody</code>,
	much like the recommendations for HTTP servers.
      </para>

      <para>
	An additional level of security can be added by specifying a
	security policy file to <command>rmid</command> by
	<programlisting> rmid -J-Djava.security.policy="..."
	</programlisting> I haven't got this to work properly yet :-(
      </para>
    </sect2>
-->

    <sect2>
      <title id="Non-lazy Services">
	Non-lazy Services
      </title>

      <note id="changed">
	<para>
	  The type of service discussed above are ``lazy'' services,
	  activated on demand when their methods are called. This
	  reduces memory use, at the expense of starting up a new JVM
	  when required. Some services need to be continuously alive,
	  but can still benefit from the log mechanism of
	  <command>phoenix</command>. If <command>phoenix</command>
	  crashes and is restarted, or the machine is rebooted and
	  <command>phoenix</command> restarts, then it is able to use
	  its log files to restart any ``active'' services registered
	  with it, as well as restore ``lazy'' services on demand.
	  This can avoid messing around with boot configuration files,
	  by making services non-lazy and just ensuring that
	  <command>phoenix</command> is started on reboot.
	</para>
      </note>
    </sect2>

    <sect2>
      <title id="Maintaining State">
	Maintaining State
      </title>

      <para>
	An activatable object is created afresh each time a method is
	called on it, using its two argument constructor. This will
	result in the object being created in the same state on each
	activation. However, method calls on objects (apart from
	<code>get...()</code> methods) usually result in a change of
	state of the object. Activatable objects will need some way of
	reflecting this change on each activation, and this is
	typically done by saving and restoring state using a disk
	file.
      </para>

      <para>
	When an object is activated, one of the parameters passed to
	it is a <classname>MarshalledObject</classname> instance. This
	is the same object that was passed to the activation system in
	the <classname>ActivationDesc</classname> parameter to
	<code>ActivationSystem.registerObject()</code>. This object
	does not change between different activations. So it cannot
	hold changing state, but only data which is fixed for all
	activations. A simple use for it is to hold the name of a file
	that can be used for state. Then on each activation, the
	object can restore state by reading stored information. On
	each subsequent method call that changes state, the
	information in the file can be overwritten.
      </para>

      <para>
	The "mutable file classifier" was discussed in an earlier
	chapter, which could be sent <code>addType()</code> and
	<code>removeType()</code> messages. It begins with a given set
	of MIME type/file extension mappings. State here is very
	simple, just storing all the file extensions and their
	corresponding MIME type in a <code>Map</code>. If we turn this
	into an activatable object, we store the state by just storing
	the map. This can be saved to disk using
	<code>ObjectOutputStream.writeObject()</code>, and retrieved
	by <code>ObjectInputStream.readObject()</code>. More complex
	cases might need more complex storage methods.
      </para>

      <para>
	The very first time a mutable file classifier starts on a
	particular host, it should build its initial state file. There
	are a variety of methods that could be used. For example, if
	the state file does not exist, then the first activation could
	detect this and construct the initial state at that time.
	Alternatively, a method such as <code>init()</code> could be
	defined, to be called once after the object has been
	registered with the activation system. 
      </para>

      <para>
	The "normal" way of instantiating an object - through a
	constructor -  doesn't work too well with activatable objects.
	If a constructor for a class doesn't start by calling another
	constructor by <code>this(...)</code> or
	<code>super(...)</code>, then the no argument superclass
	constructor <code>super()</code> is called. But the class
	<classname>Activatable</classname> doesn't have a no-args
	constructor. So you can't subclass from
	<classname>Activatable</classname> <emphasis>and</emphasis>
	have a constructor such as <code>FileClassifierMutable(String
	  stateFile)</code> that doesn't use the activation system.
	You can avoid this by not inheriting from
	<classname>Activatable</classname>, and register explicitly
	with the activation system by <emphasis>e.g.</emphasis>
	<programlisting> public FileClassifierMutable(ActivationID id,
	  MarshalledObject data) throws java.rmi.RemoteException {
	  Activatable.exportObject(this, id, 0); // continue with
	  instantiation </programlisting> Nevertheless, this is a bit
	clumsy in use: you create an object solely to build up initial
	state, and then discard it since the activation system will
	recreate it on demand.
      </para>

      <para>
	The technique adopted in this example is to create initial
	state if the attempt to restore state from the state file
	fails for any reason as the object is activated. This is done
	in the method <code>restoreMap()</code>, called from the
	constructor <code>FileClassifierMutable(ActivationID id,
	  MarshalledObject data)</code>. The name of the file is
	extracted from the marshalled object passed in as parameter.
	<programlisting> <?program
	  "src/activation/FileClassifierMutable.java"?>
	</programlisting>
      </para>

      <para>
	The difference between the server for this service and the
	last one, is that we now have to prepare a marshalled object
	for the state file, and register this with the activation
	system. Here the filename is hard-coded, but it could be given
	as a command-line argument (like services such as
	<command>reggie</command> do). <programlisting> <?program
	  "src/activation/FileClassifierServerMutable.java"?>
	</programlisting>
      </para>

      <para>
	An Ant file for this is 
	<filename>activation.FileClassifierServerMutable.xml</filename>
	<programlisting>
	  <?antFile "antBuildFiles/activation.FileClassifierServerMutable.xml"?>
	</programlisting>
      </para>

      <para>
	This example used a simple way to store state. Sun uses a far
	more complex system in many of its services such as
	<command>reggie</command>. This is a ``reliable log'', in
	package <code>com.sun.jini.reliableLog</code>. However, this
	package is not a part of standard Jini, so may change or even
	be removed in later versions of Jini. However, there is
	nothing to stop you using it if you need a robust storage
	mechanism.
      </para>
    </sect2>

    <note id="new">
      <sect2>
	<title id="Using a Configuration">
	  Using a Configuration
	</title>

	<para>
	  The service implementations shown in this chapter so far have
	  hard-coded the protocol - Jeri. In general this is not a good
	  idea, as it should be left to a runtime configuration to
	  specify this. So the code to find an exporter should be
	  handled by looking in a configuration, as we did in the
	  Configuration chapter.
	</para>

	<para>
	  The startup server is the one that will see the
	  configuration file, typically a filename as a command line
	  parameter. Previously, for non-activable services the server is able to
	  extract the exporter directly from the configuration and use
	  it to export the service. But as we have seen, it is now the
	  responsibility of the service itself to define and use an
	  exporter. The problem is how to get the command line
	  parameters from the startup server into the service's
	  constructor.
	</para>

	<para>
	  This can be solved by using the marshalled data discussed in
	  the last section: but instead of using it for state, we can
	  place the command line arguments from the server into this
	  and so pass the configuration into the client.
	</para>

	<para>
	  The changes to the service are to add in configuration code to
	  the constructor
	<programlisting> <?program
	  "src/activation/FileClassifierConfig.java"?>
	</programlisting>
	</para>

	<para>
	  The startup server marshalls the command line arguments and passes
	  them into the activation description
	<programlisting> 
	    <?program "src/activation/FileClassifierServerConfig.java"?>
	</programlisting>
	</para>

	<para>
	  An Ant file for this is 
	  <filename>activation.FileClassifierServerConfig.xml</filename>
	  <programlisting>
	    <?antFile "antBuildFiles/activation.FileClassifierServerConfig.xml"?>
	  </programlisting>
	</para>
      </sect2>
    </note>

  </sect1>

 

  <sect1>
    <title id="LeaseRenewalService">
      LeaseRenewalService
    </title>

    <para>
      Activatable objects are one example of services that are not
      continuously alive. Mobile services, such as those that will
      exist on mobile phones, are another. These services will be
      brought to life on demand (as activatable objects), or will join
      the network on occasions. These services raise a number of
      problems, and one was skirted around in the last section: how to
      renew leases when the object is not alive?
    </para>

    <para>
      Activatable objects are brought back to life when methods are
      invoked on them. The expiration of a lease does not cause any
      methods to be invoked. There is no "lease expiring event"
      generated that could cause a listener method to be invoked,
      either. It is true that a
      <classname>ServiceRegistrar</classname> such as
      <command>reggie</command> will generate an event when a lease
      changes status, but this is a "service removed" event rather
      than a "service about to be removed" event - it is too late.
    </para>

    <para>
      If a server is alive, then it can use a
      <classname>LeaseRenewalManager</classname> to keep leases alive,
      but firstly the renewal manager works by  sleeping and waking up
      just in time to renew the leases, and secondly, if the server
      exits then no <classname>LeaseRenewalManager</classname> will
      continue to run.
    </para>

    <para>
      Jini supplies a lease renewal <emphasis>service</emphasis> that
      partly avoids these problems. Since it runs as a service, it has
      an independent existence that does not depend on the server for
      any other service. It can act like a
      <classname>LeaseRenewalManager</classname> in keeping track of
      leases registered with it, and renewing them as needed. In
      general, it can keep leases alive without waking the service
      itself, which can slumber till activated by clients calling
      methods.
    </para>

    <para>
      There is a small hiccup in this: how long should the
      <classname>LeaseRenewalService</classname> keep renewing leases
      for a service? The <classname>LeaseRenewalManager</classname>
      utility has a simple solution: keep renewing while the server
      for that service is alive. If the server dies, taking down a
      service, then it will also take down the
      <classname>LeaseRenewalManager</classname> running in the same
      JVM, so leases will expire as expected after an interval.
    </para>

    <para>
      But this mechanism won't work for
      <classname>LeaseRenewalService</classname> because the managed
      service can disappear without the
      <classname>LeaseRenewalService</classname> knowing about it. So
      the lease renewal must be done on a leased basis itself! The
      <classname>LeaseRenewalService</classname> will renew leases for
      a service only for a particular amount of time, specified by a
      lease. The service will still have to renew its lease, even
      though it is with a <classname>LeaseRenewalService</classname>
      instead of a bunch of lookup services! The lease granted by this
      service should be of much longer duration than those granted by
      the lookup services for this to be of value.
    </para>

    <para>
      Activatable services can only be woken by calling one of their
      methods. The <classname>LeaseRenewalService</classname>
      accomplishes this by generating renewal events <emphasis>in
	advance</emphasis> and calling a <code>notify()</code> method
      on a listener. If the listener is the activatable object, this
      will wake it up so that it can perform the renewal. If the
      <command>rmid</command> process managing the service has died or
      is unavailable, then the event will not be delivered and the
      <classname>LeaseRenewalService</classname> can remove this
      service from its renewal list.
    </para>

    <para>
      This is not quite satisfactory for other types of "dormant"
      services such as might exist on mobile phones, since there is no
      equivalent of <command>rmid</command> to handle activation.
      Instead, the mobile phone service might say that it will connect
      once a day and renew the lease, as long as the
      <classname>LeaseRenewalService</classname> agrees to keep the
      lease for at least a day. This is still "negotiable", in that
      the service asks for a duration and the
      <classname>LeaseRenewalService</classname> replies with a value
      that might not be so long. Still, it should be better than
      dealing with the lookup services, which may ask for renewals as
      often as every five minutes.
    </para>

    <sect2>
      <title id="The Norm Service">
	The Norm Service
      </title>
      
      <note id="changed">
	<para>
	  Jini 1.1 supplied an implementation of
	  <classname>LeaseRenewalService</classname> called
	  <command>norm</command>. This was a non-lazy Activatable
	  service, which required <command>rmid</command> to be
	  running. In Jini 2.0 it has been extended to be much more
	  flexible and is controlled by various configurations
	  <orderedlist>
	    <listitem>
	      <para>
		JRMP
		<orderedlist>
		  <listitem>
		    <para>
		      transient
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      persistent
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      activatable (requires an activation server such
		      as <command>phoenix</command>)
		    </para>
		  </listitem>
		</orderedlist>
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		Jeri
		<orderedlist>
		  <listitem>
		    <para>
		      transient
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      persistent
		    </para>
		  </listitem>
		  <listitem>
		    <para>
		      activatable (requires an activation server such
		      as <command>phoenix</command>)
		    </para>
		  </listitem>
		</orderedlist>
	      </para>
	    </listitem>
	  </orderedlist> These options are all documented in the Jini
	  documentation
	  <filename>doc/api/com/sun/jini/norm/package-summary.html#examples</filename>
	</para>

	<para>
	  For example, to run the transient Jeri version
	  <programlisting>
java -Djava.security.policy=config_dir/jsk-all.policy \
     -jar install_dir/lib/start.jar \
     config_dir/start-transient-norm.config
	  </programlisting>
	  for suitable values of <filename>config_dir</filename> and
	  <filename>install_dir</filename>. 
	</para>

	<para>
	  The policy file could contain
	  <programlisting>
grant codebase "file:install_dir/lib/*" {
    permission java.security.AllPermission;
};
	  </programlisting>
	</para>

	<para>
	  The file 
	  <filename>start-transient-norm.config</filename> should contain
	  <programlisting>
import com.sun.jini.start.NonActivatableServiceDescriptor;
import com.sun.jini.start.ServiceDescriptor;

com.sun.jini.start {
    private static codebase = "http://your_host:http_port/norm-dl.jar";
    private static policy = "config_dir/jsk-all.policy";
    private static classpath = "install_dir/lib/norm.jar";
    private static config = "config_dir/transient-norm.config";

    static serviceDescriptors = new ServiceDescriptor[] {
	new NonActivatableServiceDescriptor(
	    codebase, policy, classpath,
	    "com.sun.jini.norm.TransientNormServerImpl",
	    new String[] { config })
    };
}
	  </programlisting>
	</para>

	<para>
	  This points to the <filename>transient-norm.config</filename>
	  which in turn contains
	  <programlisting>
com.sun.jini.norm {
    initialLookupGroups = new String[] { "your.group" };
}
	  </programlisting>
	  (Note that there is no mention of Jeri in any of these files:
	  presumably it is a default - the JRMP version contains a
	  definition of <filename>serverExporter</filename> as a
	  JRMPExporter.)

<!--
This is run by
<programlisting>
java -jar [setup_jvm_options] executable_jar_file 
          codebase_arg  norm_policy_file_arg
          log_directory_arg
          [groups] [server_jvm] [server_jvm_args]
</programlisting>
as in

<programlisting>
java -jar \
        -Djava.security.policy=/files/jini1_1/example/txn/policy.all \
        /files/jini1_1/lib/norm.jar \
	http://`hostname`:8080/norm-dl.jar \
        /files/jini1_1/example/books/policy.all /tmp/norm_log
</programlisting>
The first security file defines the policy that will be used for the server startup.
The file <code>norm.jar</code> contains the class files for the <command>norm</command>
service. This exports RMI stubs and the class definitions for
these are in <code>norm-dl.jar</code>. The second security file defines the
policy file that will be used in execution of the 
<classname>LeaseRenewalService</classname> methods. Finally, the log file is used to
keep state, so that it can keep track of the leases it is managing.
-->
	</para>
      </note>

      <para>
	The <command>norm</command> service will maintain a set of
	leases for a period of upto 2 hours. The
	<command>reggie</command> lookup service only grants leases
	for 5 minutes, so that using this service increases the amount
	of time between renewing leases by a factor of over twenty.
      </para>

    </sect2>
    
    <sect2>
      <title id="Using the LeaseRenewalService">
	Using the LeaseRenewalService
      </title>
      
      <para>
	The <command>norm</command> service exports an object of type
	<classname>LeaseRenewalService</classname> which is defined by
	the interface 
	<programlisting> 
package net.jini.lease; 

public  interface LeaseRenewalService { 
    LeaseRenewalSet createLeaseRenewalSet(long leaseDuration) 
          throws java.rmi.RemoteException; 
} 
	</programlisting> 
	The
	<classname>leaseDuration</classname> is a requested value in
	milliseconds for the lease service to manage a set of leases.
	The lease service creates a lease for this request, and in
	order for it to continue to manage the set beyond the lease's
	expiry, the lease must be renewed before expiration. Since the
	service may be inactive around the time of expiry, the
	<classname>LeaseRenewalSet</classname> can be asked to
	register a listener object that will receive an event
	containing the lease. This will activate a dormant listener so
	that it can renew the lease in time. If the lease for the
	<classname>LeaseRenewalSet</classname> is allowed to lapse,
	then eventually all the leases for the services it was
	managing will also expire, making the services unavailable.
      </para>

      <para>
	The <classname>LeaseRenewalSet</classname> returned from 
	<code>createLeaseRenewalSet</code>
	has interface including
	<programlisting>
package net.jini.lease;

public interface LeaseRenewalSet {
    public void renewFor(Lease leaseToRenew, 
                         long membershipDuration)
                throws RemoteException;
    public EventRegistration setExpirationWarningListener(
                         RemoteEventListener listener,
			 long minWarning,
			 MarshalledObject handback)
                throws RemoteException;
    ....
}
	</programlisting>
	The <code>renewFor()</code> method adds a new lease to the set being
	looked after. The <classname>LeaseRenewalSet</classname> will keep renewing the lease
	until either the requested <code>membershipDuration</code> expires or the
	lease on the whole <classname>LeaseRenewalSet</classname> expires (or an exception
	happens, like a lease being refused).
      </para>

      <para>
	Setting an expiration warning listener means that its <code>notify()</code>
	method will be called at least <code>minWarning</code> millseconds before
	the lease for the set expires. The event argument to this will actually be
	an <classname>ExpirationWarningEvent</classname>
	<programlisting>
package net.jini.lease;

public class ExpirationWarningEvent extends RemoteEvent {
    Lease getLease();
}
	</programlisting>
	This allows the listener to get the lease for the <classname>LeaseRenewalSet</classname>,
	and (probably) renew it. A simple activatable class that can renew the lease is
	<note id="changed">
	<programlisting>
	  <?program "src/activation/RenewLease.java"?>
	</programlisting>
	</note>
      </para>

      <para>
	The server will need to register the service and export it as
	an activatable object. This is done in exactly the same way as
	in the first example of this chapter. In addition
	<orderedlist>
	  <listitem> <para>
	      It will also need to register the lease listener (such
	      as the above <filename>RenewLease</filename>) with the
	      activation system as an activatable object
	    </para> </listitem>
	  <listitem> <para>
	      It will need to find a
	      <classname>LeaseRenewalService</classname> from a lookup
	      service
	    </para> </listitem>
	  <listitem> <para>
	      It will need to register all leases from lookup services
	      with the <classname>LeaseRenewalService</classname>.
	      Since it may find lookup services before it finds the
	      renewal service, it will need to keep a list of lookup
	      services found before finding the service, in order to
	      register them with it
	    </para> </listitem>
	</orderedlist> 
	<note id="changed">
	<programlisting> 
	  <?program "activation/FileClassifierServerLease.java"?>
	</programlisting>
	</note>
      </para>

      <note id="new">
      <para>
	An Ant file to build, deploy and run the service is
	<filename>activation.FileClassifierServerLease.xml</filename>
	<programlisting>
	  <?antFile "antBuildFiles/activation.FileClassifierServerLease.xml"?>
	</programlisting>
      </para>

      <para>
	In order to run the server, the following need to be running
	<orderedlist>
	  <listitem>
	    <para>
	      <code>reggie</code> to run as a lookup service
	    </para>
	  </listitem>
	  <listitem>
	    <para>
	      <code>phoenix</code> to act as an activation server for the 
	      <filename>FileClassifier</filename> service, and also for the
	      <filename>RenewLease</filename> service
	    </para>
	  </listitem>
	  <listitem>
	    <para>
	      <code>norm</code> as a lease renewal service. Each lease will be
	      registered with this, and it will have the <filename>RenewLease</filename>
	      as listener for expiration events
	    </para>
	  </listitem>
	</orderedlist>
	The server starts, finds lookup services and registers the service with each
	of them. Each lease that it gets is also registered with the lease renewal
	service, and the listener is also registered. The server then terminates.
	The lease renewal service renews leases with the lookup service. When the
	lease renewal set is about to expire it wakes up the lease renewal listener
	which renews the set. Note that since the listener is activatable, this
	"wakeup" is performed by the activation server <command>phoenix</command>.
	"trace" messages from the listener thus appear in whatever window the
	activation server is run from!
      </para>
      </note>
    </sect2>
    
  </sect1>

 <note id="new">
    <para>
      !!! I HAVEN'T MADE ANY CHANGES BEYOND THIS POINT YET !!!
    </para>
  </note>

<sect1>
<title id="LookupDiscoveryService">
LookupDiscoveryService
</title>
    
    <para>
      It is easy enough for a server to discover all of the lookup
      services within reach at the time it is started, using
      <classname>LookupDiscovery</classname>. While the server
      continues to stay alive, any new lookup services that start will
      also be found by <classname>LookupDiscovery</classname>. But if
      the server terminates, which it will for activable services,
      then these extra lookup services will probably never be found.
      This will result in the service not being registered with them,
      which could mean in turn that clients may not find it. This is
      analogous to leases not being renewed if the server terminates.
    </para>

    <para>
      From Jini 1.1, there is a
      <classname>LookupDiscoveryService</classname>, that can be used
      to continuously monitor the state of lookup services. It will
      monitor these on behalf of a service that will most likely want
      to register with each new lookup service as it starts. If the
      service is an activatable one, the the server that would have
      done this will have terminated, as its role would have just been
      to register the service with <code>phoenix</code>.
    </para>

    <para>
      When there is a change to lookup services, the
      <classname>LookupDiscoveryService</classname> need to notify an
      object about this, by sending it a remote event (actually of
      type <classname>RemoteDiscoveryEvent</classname>). But again, we
      do not want to have a process sitting around waiting for such
      notification, so the listener object will probably also be an
      activatable object. 
    </para>

    <para>
      The <classname>LookupDiscoveryService</classname> 
      interface has specification
      <programlisting>
public interface LookupDiscoveryService {
    LookupDiscoveryRegistration register(String[] groups,
                                         LookupLocator[] locators,
                                         RemoteEventListener listener,
                                         MarshalledObject handback,
                                         long leaseDuration);
}
      </programlisting>
      Calling the <code>register()</code> method will begin a multicast search
      for the groups, and unicast lookup for the locators. The registration is
      leased, and will need to be renewed before expiry (a lease
      renewal service can be used for this). Note that the listener
      <emphasis>cannot</emphasis> be <code>null</code> - this is simple
      sanity checking, for if the listener was <code>null</code> 
      then the service
      could never do anything useful!
    </para>

    <para>
      A lookup service in one of the groups can start or terminate. Or it can 
      change its group membership in such a way that it now does (or doesn't)
      meet the group criteria. A lookup service in the locators list can 
      also start or stop. These will generate <classname>RemoteDiscoveryEvent</classname> events
      and call the <code>notify()</code> method of the listener. The event interface
      includes
      <programlisting>
package net.jini.discovery;

public interface RemoteDiscoveryEvent {
    ServiceRegistrar[] getRegistrars();
    boolean isDiscarded();
    ...
}
      </programlisting>
      The list of registrars is the set that triggered the event. The 
      <code>isDiscarded()</code> method is used to check if it is a 
      "discovered"
      lookup service or a "discarded" lookup service. 
      An initial event is not posted when the listener is registered: the set
      of lookup services that are initially found can be retrieved from the
      <classname>LookupDiscoveryRegistration</classname> 
      object returned from the
      <code>register()</code> method, by its <code>getRegistrars()</code>.
    </para>

    <note id="changed">
    <sect2>
      <title id="Fiddler">
	The Fiddler Service
      </title>

      <para>
	The Jini 1.1 release includes an implementation of the lookup discovery
	service, called <code>fiddler</code>. This has been modified in Jini
	2.0 to be more flexible. It can be run in three modes, using either
	Jeri (the default) or JRMP
	<orderedlist>
	  <listitem>
	    <para>
	      transient
	    </para>
	  </listitem>
	  <listitem>
	    <para>
	      persistent
	    </para>
	  </listitem>
	  <listitem>
	    <para>
	      activatable (requires <command>phoenix</command> to be
	      running)
	    </para>
	  </listitem>
	</orderedlist>
	Information about how to run <command>fiddler</command> in each
	mode is given in the Jini download, under
	<filename>file:///usr/local/jini2_0/doc/api/com/sun/jini/fiddler/package-summary.html</filename>
      </para>

      <para>
	To run <command>fiddler</command> in transient mode using Jeri over TCP,
	a command line such as this needs to be executed
	<programlisting>
java \
  -Djava.security.manager= \
  -Djava.security.policy=fiddler-start-transient.policy \
    -jar jini_install_dir/lib/start.jar \
           config/fiddler-start-transient.config
	</programlisting>
	where <filename>fiddler-start-transient.policy</filename> could be
	the same as <filename>policy.all</filename>
      </para>

      <para>
	The contents of <filename>fiddler-start-transient.config</filename>
	could be
	<programlisting>
import com.sun.jini.start.NonActivatableServiceDescriptor;
import com.sun.jini.start.ServiceDescriptor;

com.sun.jini.start {

    private static serviceCodebase   = 
            new String("http://myHost:8080/fiddler-dl.jar");
    private static servicePolicyFile = 
            new String("example_install_dir${/}policy${/}jeri-transient-fiddler.policy");
    private static serviceClasspath  = 
            new String("jini_install_dir${/}lib${/}fiddler.jar");
    private static serviceImplName   = 
            new String("com.sun.jini.fiddler.TransientFiddlerImpl");
    private static serviceConfig     = 
            new String("example_install_dir${/}config${/}jeri-transient-fiddler.config");
    private static serviceArgsArray  = new String[] { serviceConfig };

    private static nonActivatableServiceDescriptor =
                   new NonActivatableServiceDescriptor(serviceCodebase,
                                                       servicePolicyFile,
                                                       serviceClasspath,
                                                       serviceImplName,
                                                       serviceArgsArray);
    static serviceDescriptors = 
                 new ServiceDescriptor[] { nonActivatableServiceDescriptor };

}//end com.sun.jini.start
	</programlisting>
	The configuration file 
	<filename>jeri-transient-fiddler.config</filename> would contain
	<programlisting>
import net.jini.jeri.BasicILFactory;
import net.jini.jeri.BasicJeriExporter;
import net.jini.jeri.tcp.TcpServerEndpoint;

com.sun.jini.fiddler {

    private invocationLayerFactory = new BasicILFactory();
    serverExporter = new BasicJeriExporter(TcpServerEndpoint.getInstance(0),
                                           invocationLayerFactory,
                                           false,
                                           true);

    initialLookupGroups = new String[] {"myGroup.myCompany.com"};

}//end com.sun.jini.fiddler
</programlisting>
      </para>

    </sect2>
    </note>

    <note id="changed">
    <sect2>
      <title id="Using the LookupDiscoveryService">
	Using the LookupDiscoveryService
      </title>
      
      <para>
	An activatable service can make use of a lease renewal service
	to look after the leases for lookup services discovered. How
	it finds these lookup services can be by means of a lookup
	discovery service. The logic to manage these two services
	could be a little tricky as we attempt to find two different
	services. We can simplify for this example by just doing a
	sequential search using a
	<classname>ServiceDiscoveryManager</classname> 
      </para>

      <para>
	While lease management can be done by the lease renewal
	service, the lease renewal set will also be leased and will
	need to be renewed on occasions. The lease renewal service can
	call an activatable <classname>RenewLease</classname> object
	to do this, as in the last section.
      </para>

      <para>
	The lookup discovery service is also a leased service - it
	will only report changes to lookup services while its
	<emphasis>own</emphasis> lease is current. So the lease from
	this service will have to be managed by the lease renewal
	service, in addition to the leases for any lookup services
	discovered.
      </para>

<para>
	The primary purpose of the lookup discovery service is to call
	the <code>notify()</code> method of some object when
	information about lookup services changes. This object should
	also be an activatable object. We define a
	<classname>DiscoveryChange</classname> object with method
	<code>notify()</code> to handle changes in lookup services. If
	a lookup service has disappeared, we don't worry about it. If
	a lookup service has been discovered, we want to register the
	service with it, and then manage the resultant lease. This
	means that the <classname>DiscoveryChange</classname> object
	must know both the service to be registered, and the lease
	renewal service. This is static data, so these two objects can
	be passed in an array of two objects as the
	<classname>MarshalledObject</classname> to the activation
	constructor. The class itself can be implemented as
	<programlisting> 
	  <?program "activation/DiscoveryChange.java"?>
	</programlisting>
      </para>

      <para>
	The server must install an activation group, and then find
	activation proxies for the service itself and also for our
	lease renewal object. After this, it can use a
	<classname>ClientLookupManager</classname> to find the lease
	service, and register our lease renewal object with it. Now
	that it has a proxy for the service object, and also a lease
	renewal service, it can create the marshalled data for  the
	lookup discovery service and register this with
	<command>rmid</command>. Now we can find the lookup discovery
	service, and register our discovery change listener
	<classname>DiscoveryChange</classname> with it. At the same
	time, we have to register the service with all the lookup
	services the lookup discovery service finds on initialisation.
	This all leads to <programlisting> 
	  <?program "activation/FileClassifierServerDiscovery.java"?>
	</programlisting>
      </para>

      <para>
	In order to run this example, you need to
	<orderedlist>
	  <listitem>
	    <para>
	      Run a lookup service <command>reggie</command>
	    </para>
	  </listitem>
	  <listitem>
	    <para>
	      Run an activation server <command>phoenix</command>
	    </para>
	  </listitem>
	  <listitem>
	    <para>
	      Run a lease renewal service <command>norm</command>
	    </para>
	  </listitem>
	  <listitem>
	    <para>
	      Run a lookup discovery service <command>fiddler</command>
	    </para>
	  </listitem>
	  <listitem>
	    <para>
	      Run the server. This will terminate, hopefully after finding
	      the services and registering the 
	      <filename>DiscoveryChange</filename> with the lookup
	      discovery service, and register the leases for the service and
	      the discovery service
	    </para>
	  </listitem>
	</orderedlist>
	An Ant file to build, deploy and run the service is
	<filename>activation.FileClassifierServerDiscovery.xml</filename>
	<programlisting>
	  <?antFile "antBuildFiles/activation.FileClassifierServerDiscovery.xml"?> 
	</programlisting>
      </para>
    </sect2>
    </note>

  </sect1>


<sect1>
<title id="Summary">
Summary
</title>

<para>
Some objects may not always be available, either because of mobility issues or because
they are activatable objects. This chapter has dealt with activatable objects, and
also with some of the special services that are needed to properly support these
transient objects.
</para>

</sect1>

&copyright;
</chapter>
