<?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 title="Jini and Servlets">
<title>
Jini and Servlets
</title>

<tocchap>
<title>
Contents
</title>

<toclevel1>
<tocentry>
  <ulink url="#Dynamic Web pages">Dynamic Web pages</ulink>
</tocentry>
<tocentry>
  <ulink url="#Servlets">Servlets</ulink>
</tocentry>
<tocentry>
  <ulink url="#Jakarta Tomcat Configuration">Jakarta Tomcat Configuration</ulink>
</tocentry>
<tocentry>
  <ulink url="#Servlet as Jini client">Servlet as Jini client</ulink>
</tocentry>
<tocentry>
  <ulink url="#FileClassifierServlet">FileClassifierServlet</ulink>
</tocentry>
<tocentry>
  <ulink url="#Deploying the Servlet">Deploying the Servlet</ulink>
</tocentry>
</toclevel1>
</tocchap>

<abstract>
<para>
People are becoming increasingly accustomed to "finding things
on the Web." The pages they view may be static or may be produced dynamically
by a variety of technologies such as CGI scripts, Active Server Pages,
Java servlets, Java Server Pages, etc. This chapter looks at how servlets
can be written that use Jini services to generate content.
</para>
</abstract>

<sect1>
<title id="Dynamic Web pages">
Dynamic Web pages
</title>

<para>
Along with email, the Web is the most widely used internet service used
by most people. The explosive growth in the number of Web pages over the
years has led people to just "look for it on the Web." 
</para>

<para>
Initially all Web pages were static HTML documents, existing as files
on an HTTP server. CGI (Common Gateway Interface) was introduced as a
means of generating content dynamically. A CGI script is a program
called by the HTTP server to handle a document request, and the
program is expected to write a valid HTML (or other) document to 
its standard output which is returned to the user.
</para>

<para>
CGI scripts may be written in any language, but gain their name because
the languages used are often scripting languages such as one of the Unix
shells, Perl, Python, etc. However, any language can be used such as
C, C++, Eiffel - just as long as a single program can be called which will
process the request.
</para>

<para>
Java is not good for CGI scripts, because it requires calling a runtime
engine such as <code>jre</code> with an argument that is the class
to load so it can call the <code>main()</code> method. That is, starting
a Java program requires calling the runtime with an additional 
argument, and CGI is not designed to deal with such situations.
Rather clumsily,
to use a Java class as CGI script requires writing a shell script or
DOS batch file that calls the Java runtime with class name as argument.
</para>

<para>
CGI scripts have other drawbacks: each invocation of a CGI script
runs as a separate process. This causes runtime overheads, as it may
involve loading and starting a runtime interpreter such as the Java, 
Perl, tcl or shell interpreters. These are all large programs with
substantial initialisation processing, and having to repeat this for
each CGI call can waste large amounts of time.
</para>

<para>
Loadable modules are employed to reduce these overheads. These are loaded
into an HTTP server and run as part of that server. This means that startup
is only done once rather than on each invocation. In addition, the module
can have access to the internals of the HTTP server and can use this to 
optimise calls even more. By running only once instance of  the module,
there are also other benefits such as easy sharing of state information across
different calls to the module.
</para>

</sect1>

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

<para>
Java servlets are just one method of embedding an interpreted
language into an HTTP server. The language in this case is Java, and
the particular API's exposed are now part of the Java standards. 
Why a servlet is of more interest than other systems is that it can 
allow us to access Jini services and use them within the servlet,
which would be impossible say, for Perl modules.
</para>

<para>
A servlet typically extends <code>HttpServlet</code>. It will
usually override the methods
<programlisting>
public void init();
public void doGet(HttpServletRequest request,
                  HttpServletResponse response);
        throws IOException, ServletException
public void doPost(HttpServletRequest request,
                   HttpServletResponse response)
        throws IOException, ServletException;
</programlisting>
</para>

<para>
The <code>init()</code> method is called when the servlet is first
loaded, and can be used to perform once-off initialisation.
The <code>doGet()</code> and <code>doPost()</code> methods are
called from HTTP <code>GET</code> and <code>POST</code> requests, 
respectively. Usually you implement one of these in full, and just
make the other one call the first.
</para>

<para>
The <code>request</code> and <code>response</code> parameters are
used to get information from the HTTP request and to pass information
back as an HTML document. In particular, output of the HTML
reply document is done by getting a <code>PrintWriter</code> from
<code>response</code> and writing to it:
<programlisting>
PrintWriter out = response.getWriter();
out.println("&amp;lt;html&amp;gt;");
out.println("&amp;lt;head&amp;gt;");
out.println("&amp;lt;title&gt;" + "Jini Service Finder" + "&amp;lt;/title&amp;gt;");
out.println("&amp;lt;/head&amp;gt;");
out.println("&amp;lt;body&amp;gt;");
// etc
</programlisting>
</para>

</sect1>

<sect1>
<title id="Jakarta Tomcat Configuration">
Jakarta Tomcat Configuration
</title>

<para>
A Java servlet is called from a servlet engine such as the Jakarta
Tomcat engine which is part of the Apache server project. This
engine can be run as a module within an Apache HTTP server, or can be
run as a standalone HTTP server which also interprets servlet calls.
</para>

<para>
The remainder of this section deals with the Jakarta Tomcat server
in standalone mode, but much is applicable to running it as an Apache
module. Some of this section may be relevant to other  servlet engines.
We shall discuss Jakarta Tomcat version 3.1 - due to problems with
security managers, earlier versions of Tomcat will not work with Jini.
</para>

<para>
Tomcat must be run with a security manager. This is done under Unix by calling
<programlisting>
tomcat.sh start -security
</programlisting> 
with a similar batch file for MSDOS. Unfortunately, this fails
due to a bug in the shell script. In line 124 of the script occurs
<programlisting>
  if [ "$1" = "-security" ] ; then
    echo Starting with a SecurityManager
    $JAVACMD $TOMCAT_OPTS -Djava.security.manager -Djava.security.policy==${TOMCAT_HOME}/conf/tomcat.policy -Dtomcat.home=${TOMCAT_HOME}  org.apache.tomcat.startup.Tomcat "$@"
</programlisting> 
The Java runtime then complains about an unrecognised option
<code>-security</code>. A <code>shift</code> operation is missing to
lose this option:
<programlisting>
  if [ "$1" = "-security" ] ; then
    echo Starting with a SecurityManager
    shift    # lose the -security option
    $JAVACMD $TOMCAT_OPTS -Djava.security.manager -Djava.security.policy==${TOMCAT_HOME}/conf/tomcat.policy -Dtomcat.home=${TOMCAT_HOME}  org.apache.tomcat.startup.Tomcat "$@"
</programlisting>
</para>

<para>
This runs Java with a security manager - and a security policy file.
The policy file supplied with Tomcat will run Java servlets, but not
Jini clients. The policy file needs to be extended with the extra
permissions needed by Jini clients. You have the choice of either
adding the extra security options to the <code>tomcat.policy</code>
file, or pointing to another file with the correct permissions. 
</para>

<para>
You may not have the necessary permissions to modify the script files.
For example, if the system supervisor has installed Tomcat then you
won't have write permission on these files. Certain other configuration
files control things like the port Tomcat listens on, and you won't
be able to modify those either. So you may need to negotiate changes
with your sysadmin, or run a private copy of Tomcat.
</para>

<para>
Whoever is in charge of servlet security is unlikely to let you use an
<code>AllPermission</code> policy. You will probably need to add permissions
one by one to the servlet policy file, which will be a tedious process.
You can get debug information from Apache Tomcat version 5.5 by setting an
environment variable:
<programlisting>
export CATALINA_OPTS=-Djava.security.debug=all    (Unix)
set CATALINA_OPTS=-Djava.security.debug=all       (Windows)
</programlisting>
</para>

<para>
Tomcat uses port 8080 by default. The HTTP server started
by <code>reggie</code> also uses port 8080. If you are using Tomcat
and the <code>reggie</code> lookup service on the same machine then 
one of these needs to be set to use a different port.
To change Tomcat, you need to modify 
<code>$TOMCAT_HOME/conf/server.xml</code>.
</para>

<para>
A servlet that acts as a Jini client must know the Jini libraries.
It is enough to put the Jini jar files in the <code>CLASSPATH</code>
before Tomcat is run. Tomcat will add its own entries to the class path.
</para>

<para>
If your servlet client installs Jini event listeners in Jini services that
it discovers, then the client must set the 
<code>java.rmi.server.codebase</code> property to include the listener's
class files, so that the service can install the listener properly.
Most clients will be aware that they are installing an event listener,
but not always: if the <code>ServiceDiscoveryManager</code> is used,
then it installs event listeners. The Sun implementation needs the class
<code>
net/jini/lookup/ServiceDiscoveryManager$LookupCacheImpl$LookupListener_Stub.class
</code> to be accessible from an HTTP server. 
</para>

<para>
Tomcat does not set the <code>java.rmi.server.codebase</code> property.
The startup script needs to be modified again to add this to the
Java runtime command.
</para>
</sect1>

<sect1>
<title id="Servlet as Jini client">
Servlet as Jini client
</title>

<para>
Once appropriate security permissions have been set up, a Java servlet
can act as a Jini client. The "brute force" way is to run everything
from each of the HTTP request methods. So in <code>doGet()</code>
we might look for lookup services, then query them for a desired service,
fetch the service and then finally invoke the service. This works: it is
just awfully slow and will often take several minutes (which seems
like hours in internet time...).
</para>

<para>
The tricks to get workable clients are to minimise repeated work, and
to run caching mechanisms in separate threads, so that information is
available immediately when an HTTP request comes in. This means
<orderedlist>

<listitem>
if a lookup service is at a known address, then don't search for it
on every HTTP request, but find it <emphasis>once</emphasis> 
in the <code>init()</code> method. Then store it in a field available
to every HTTP request or in a session object.
</listitem>

<listitem>
if you need to monitor changes in services registered on a lookup
service, then add a listener by <code>registrar.notify()</code>
which will be called asynchronously when changes occur.
</listitem>

<listitem>
if you need to have a particular service available immediately, then
keep a cache by using a <code>ServiceDiscoveryManager</code> which
will use its own thread to keep the cache up to date. (But then
you have to remember to modify the startup script to set the
<code>java.rmi.server.codebase</code> property.)
</listitem>
</orderedlist>
</para>

</sect1>

<!--
<sect1>
<title id="Lookup Service Monitor">
Lookup Service Monitor
</title>

<para>
In this section we shall show how to build a servlet which acts as
a Jini client to monitor the services available on a known Jini
lookup service. That is, we shall build a web page that will show
the services available on a particular lookup server. This program
is the basis of a servlet that can be used to browse services
that will be available from <code>http://www.jini.monash.edu.au</code>.
</para>

<sect2>
<title>
ServiceFinder
</title>

<para>
The <code>ServiceFinder</code> interface will return the list of
services that it knows about:
<programlisting>
<?program "common/ServiceFinder.java"?>
</programlisting>
and has a remote interface of 
<programlisting>
<?program "servlet/RemoteServiceFinder.java"?>
</programlisting>
(I am putting the classes that will be used be used by servlets
into a <code>servlet</code> package because that suits the organisation
of this book, in which servlets only form a single chapter. 
But if you have lots of servlet classes you may want to
use a different package naming scheme.)
</para>

</sect2>

<sect2>
<title>
Server
</title>

<para>
A server is needed to create a service implementation of the interface.
We want the implementation to find a given lookup service and to 
keep track of all the services that are registered with it. A server
that will create the implementation is
<programlisting>
<?program "servlet/Server.java"?>
</programlisting>
</para>

</sect2>

<sect2>
<title>
Service Implementation
</title>

<para>
The service implementation can be done by

<programlisting>
<?program "servlet/ServiceFinderImpl.java"?>
</programlisting>
</para>

</sect2>

<sect2>
<title>
Standalone client
</title>

<para>
We want to build a client that is a servlet. Before doing so, we
will build an ordinary standalone client that we can run to check
that the service is working okay without having to worry about
aditional servlet issues.
</para>

<para>
A suitable client is
<programlisting>
<?program "client/ServiceViewer.java"?>
</programlisting>
</para>

</sect2>

</sect1>
-->

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

<para>
The file classifier can be turned into a simple Web servlet that
illustrates some of the techniques to use servlets and to make
them appear responsive rather than horribly slow.
A Web interface to a file classifier will firstly display a form
for entry of data such as 
<programlisting>
&amp;lt;form action="..."&amp;gt;
File Name &amp;lt;input type="textfield" name="filename"&amp;gt;
&amp;lt;input type="Submit"&amp;gt;
&amp;lt;/form&amp;gt;
</programlisting>
When this form is submitted, the servlet will get the <code>filename</code>
field and call the file classifier service for this filename.
The result will be returned as an HTML document.
</para>

<para>
We will use a single servlet both for the initial form and for the
reply. The initial form could have been done from a static HTML page,
but making it into a servlet call means that we will invoke the
method <code>init()</code> if this is the first time this servlet
has been called. That is, the first time that a user shows interest
in the service, we can start processing for this service.
</para>

<para>
The <code>ServiceDiscoveryManager</code> is of great use here.
We can use it to start building a cache of services
<emphasis>which runs in a separate thread</emphasis>. 
So <code>init()</code> can start the cache and return immediately. 
</para>

<para>
The call to <code>doGet()</code> can determine if the
<code>filename</code> property is set. If not, it returns the initial
form entry page. If set, then it can query the cache for a service
and use it. By this stage, there is a strong chance that the cache
will have something in it. To get to this stage, the following
activities will have occurred
<orderedlist>
<listitem>
  <code>init()</code> will have started cache building in a separate thread
</listitem>
<listitem>
  <code>doGet()</code> will have returned a form to the user
</listitem>
<listitem>
  The user will have spent time filling in the form and submitting it
</listitem>
<listitem>
  <code>doGet()</code> will be able to use a non-empty cache of services
  without delay
</listitem>
</orderedlist>
In the majority of cases, this will give fast response.
</para>

<para>
There are of course a variety of complexities that can be added to this
<orderedlist>
<listitem>
  Initial page delivery can be done by a different servlet, in which case
  the two servlets will need to communicate the cache between them 
</listitem>
<listitem>
  Filling the cache may take longer than the user submitting the form.
  The following program just says "Try again", but you could add delays
  until the cache has an entry
</listitem>
<listitem>
  Someone who calls the submission page directly, without going through
  the initial form will probably beat cache filling if this is the
  first time this servlet has been called. This is highly unlikely,
  but possible. The servlet would then fail to find a service
  until called again
</listitem>
</orderedlist>
These add to complexity, but not to basic concepts.
</para>

<para>
A servlet based on the above discussion is
<programlisting>
<?program "servlet/FileClassifierServlet.java"?>
</programlisting>
</para>
</sect1>

<sect1>
<title id="Deploying the Servlet">
Deploying the Servlet
</title>

<para>
The servlet class <code>FileClassifierServlet</code> needs to be located where
the servlet engine can locate it. There is now a standard naming
convention for locating servlet classes under a complex directory
structure. If the servlet is meant to be accessed from, say, the url
<code>http://www.jini.monash.edu.au:8088/jini/servlet/servlet.FileClassifierServlet</code>
where the servlet engine is Tomcat, then the class file
needs to be copied to
<programlisting>
$TOMCAT_HOME/webapps/jini/WEB-INF/classes/servlet/servlet/FileClassifierServlet.class
</programlisting>
(There is an unfortunate repitition of the <code>servlet</code> part here.
The first occurrence distinguishes between servlets and jsp's. The
second occurrence is part of the package name, and reflects the package
naming structure we have used in this book.)
</para>

</sect1>

&copyright;
</chapter>
