Skip to main content.

Web Based Programming Tutorials

Homepage | Forum - Join the forum to discuss anything related to programming! | Programming Resources

Java Expert Solutions

Chapter 25 -- Writing Web Services for Jigsaw

Chapter 25

Writing Web Services for Jigsaw

by David P. Boswell


CONTENTS



Jigsaw is the first Web server written entirely in Java that is freely available and uses HyperText Transport Protocol (HTTP). Two of its major design goals are portability and extensibility. The Jigsaw server runs on most machines for which a Java environment is available. The author has tested the server in a number of these environments. Some examples are Microsoft Windows 95/NT, SunMicrosystems Solaris, and Linux. This chapter was developed using Jigsaw running on Linux 2.0 and a port of the Sun JDK. It was also tested with the Kaffe Java interpreter. The Jigsaw server can be extended by writing new resource objects in Java. One possible extension would be a replacement for CGI scripts. Using this extension does not preclude the use of normal CGI scripts. The support of regular CGI scripts allows you to migrate existing CGI applications into Jigsaw. Portability adds tremendous value to the Jigsaw server when you select a hardware and software base for your Web applications. This chapter focuses on the extensibility of the server.

Architectural Overview

Jigsaw is an object-oriented Web server. Each resource exported by the server is mapped to a Java object. Each resource can be configured independently and maintains its own state through a persistency mechanism provided by the Jigsaw runtime.

The major components of the Jigsaw server are the daemon module and the resource module.

Handling the HTTP Protocol with the Daemon Module

The daemon module deals with HTTP. It handles incoming connections creates new client objects, decodes requests, and sends replies.

The most important part of the daemon module is the HTTPD object. This object runs the main processing loop of the server handling incoming connections and managing other objects in the server process, such as:

Managing the Server Information Space with the Resource Module

The resource module is responsible for managing the information space of the server. Each exported resource is mapped to an instance of an HTTPResource. Each instance is created at configuration time, either manually or by the resource factory.

The resource factory creates HTTPResource instances out of existing data. Jigsaw can handle files and directories provided by the underlying file system. Like the rest of Jigsaw, you can extend the resource factory to handle more objects.

The resource module uses two databases, accessible via a forms-based interface. The extension database /Admin/Extensions and the directory template database are accessible at /Admin/DirectoryTemplates.

Maintaining Server State via Object Persistence

Jigsaw resources are persistent objects. They maintain their state across server invocations. A resource that wraps an existing object is created only once during the lifetime of the server. Changing the configuration after a resource has been indexed has no effect on resources that have already been created.

This design feature speeds up the server because indexing an existing object into a resource is a costly process involving the querying of multiple databases, such as the extensions and directory templates database.

If you want to change the configuration of a resource and reindex a selected part of your information space, the DirectoryResourceEditor object accessible via http://your-host.your-domain:9999/Admin allows you to reindex resources as needed.

If you want the whole site to be reindexed, stop the server, delete all .jigidx files, and restart it. This causes the server to reindex the whole site when it is restarted.


Tip
To do this quickly under UNIX, change to the root of your Jigsaw tree.
Then issue the following command:
find . -name .jigidx -exec rm {} \;
Under Windows: Start the Windows Explorer and select your Jigsaw directory. Select Tools, Find Files or Folders. Type .jigidx in the Names dialog box (note the leading "dot"). Choose Edit Select All and File Delete.

Pre and Post Request Processing with Resource Filters

The final important concept of Jigsaw is resource filters. A resource filter is a Java resource that contains a set of attributes and one or more methods. Like all other Jigsaw resources, its attributes are persistent. This provides some powerful possibilities, as you will see later in the filter example

Each HTTP request is processed by a target resource instance. Most resource classes provided by Jigsaw inherit from the FilteredResource class. All instances of this class inherit a set of filters that are subclasses of ResourceFilter.

This provides a callback to the filter twice during resource processing. Once during lookup, before the target has been selected, the ingoingFilter method is called with the request as a parameter. After the request has been processed by the target resource, the outgoingFilter method is called with both the request and reply as parameters.

Jigsaw Interface

Jigsaw provides many classes and attributes, listed in Table 25.1, that you can use to extend and control the behavior of the server. For the sake of space, you will only look at classes central to the Jigsaw server design, or those needed by the examples.

The HTTPResource Class

HTTPResource is the base class of all resources accessible through HTTP. It does not provide any implementation of the HTTP methods.

Table 25.1  Attributes Defined by HTTPResource

AttributeDescription
parent The parent of a resource is the resource that is responsible for its loading in memory. All resources should have a parent, except for the server's root resource, whose parent is null. type: This attribute is a computed ObjectAttribute.default value: This attribute defaults to that of the resource that loaded it into memory.
Url This is the location of this resource within the servers exported name-space. It is a string that is parseable into a Java URL.type: This attribute is a computed StringAttribute. default value: This attribute defaults to the concatenation of the resource's parent URL attribute with its own name or identifier.
Server This is the name of the server that makes this resource accessible through HTTP.type: This attribute is a computed ObjectAttribute.default value: This attribute defaults to its parent's server attribute value.
Quality This is a rating of the quality of this resource's content. The rating is a number between 0.0 and 1.0. It is used by the NegotiatedResource to select among its set of variants. type: This attribute is a editable DoubleAttribute. default value: This attribute defaults to 1.0.
title This is the title of this resource. This attribute can be computed from the resource content if the content is an HTML file that has some <META> tag, or if it is provided for informational purposes even if the resource's content type is not text/html. type: This attribute is a computed and/or editable StringAttribute. default value: This attribute is undefined.
Content-language This is the language of the resource. It is used by the NegotiatedResource to select among its set of variant resources.The value of this attribute can be extracted from the resource content if it is an HTML file that includes some appropriate <META> tag. Otherwise, it is provided for informational purposes.type: This attribute is a computed and/or editable LanguageAttribute. default value: This attribute is undefined.
Content-encoding This is the encoding method. This can only be a single token as described in the HTTP/1.0 protocol specification. type: This attribute is a computed and/or editable EncodingAttribute. default value: This attribute is undefined.
Content-type This is the MIME type of the resource. type: This attribute is a computed and/or editable MIMETypeAttribute.default value: This attribute is undefined.
Content-length This is the length of the resource's content. type: This attribute is a computed IntegerAttribute. default value: This attribute is undefined. It is up to subclasses of this resource to either generate it dynamically or cache it from the FileResource. The FileResource gets this information from calls to the file system.
Last-modified This is the date of the last modification to this resource. type: This attribute is a computed and/or editable DateAttribute. default value: This attribute is undefined. See the default value of content-length above for additional information.
Expires This is the date on which this resource expires. type: This attribute is a computed and/or editable DateAttribute. default value: This attribute is undefined. See the default value of content-length above for additional information.
Icon This is any icon to be associated with this resource. type: This attribute is an editable StringAttribute. default value: This attribute is undefined.
Maxage This attribute defines the allowed drift between the real content of a resource and the one that is sent as request replies. The bigger this value, the more efficient the server can be, since it can reuse cached request replies for a longer time. This attribute takes affect only if it is defined and if the resource provides a meaningful last-modified attribute value. type: This attribute is an editable IntegerAttribute. default value: This attribute is undefined.

The FilteredResource Class

A filtered resource is the resource that supports filters. By itself, a filtered resource does not define any new attributes. However, each of the filters attached to the resource maintain a shadow copy of the target resource attribute values.

So a filtered resource attribute value is looked up this way: First, all its filters are queried to locate the attribute needed. If one of them defines the attribute, then this value is returned.

This allows filters to shadow attribute values based on the processing they do on the resource reply. Otherwise, the appropriate filtered resource attribute value is returned. The FilteredResource class inherits from HTTPResource.

The DirectoryResource Class

The directory resource is the basic resource to export file-system directories. It keeps track of all its children resources, creates them dynamically if needed, and is also able to create negotiated resources on-the-fly. The DirectoryResource class inherits HTTPResource and FilteredResource (see Table 25.2).

Table 25.2  Attributes of DirectoryResource

AttributeDescription
directory This is the physical directory that this resource exports. type: This attribute is a computed FileAttribute and is not saved.default value: This attribute is computed by concatenating, in the appropriate file-system-dependent way, the parent's resource directory value with this directory identifier.
storeid This is the name of the file to be used as the resource store database in this directory. type: This attribute is an editable FilenameAttribute and is mandatory. default value: This attribute is computed by concatenating, in the appropriate file-system-dependent way, the parent's resource directory value with this directory identifier.
relocate Should the directory produce a relocation reply when accessed through an invalid URL? A common way of handling invalid directory access is to produce a relocation reply so that the browser gets access to the directory through a valid URL. The URL http://www.w3.org/pub is invalid because pub is a directory. The correct URL is http://www.w3.org/pub/. When this flag is set to true, the directory resource produces the appropriate relocation reply. type: This attribute is an editable BooleanAttribute and is not saved. default value: This attribute value defaults to true.
extensible Should this directory automatically stay in sync with the underlying physical directory? The directory resource maintains a cache of its list of children, which may be outdated if you change the directory through direct file system access.When this flag is true, the directory resource makes its best effort to stay in sync with the file system by adopting the following lookup algorithm. First, look up children in the cache list. If this fails, check to see if an appropriate file exists. If such a file exists, hand it to the ResourceIndexer and install the resulting resource, if any, as a new child of the directory resource.type: This attribute is an editable BooleanAttribute. default value: This attribute defaults to true.
index This attribute should name an existing child resource that will be used as the index resource of the directory. All accesses to the directory will be delegated this resource. type: This attribute is an editable StringAttribute. default value: This attribute is computed by concatenating, in the appropriate file-system-dependent way, the parent's resource directory value with this directory identifier.
icondir This is the name of a directory that holds the icons for this directory. Each HTTPResource has an optional icon attribute. When a directory resource needs to produce a listing it dereferences each icon relative to its icon directory. type: This attribute is an editable StringAttribute, specifying the path tothe icon directory. default value: This attribute defaults to /icons.
dirstamp This is the date on which the directory resource last checked its consistency against the underlying physical directory. type: This attribute is a computed DateAttribute that is noneditable.default value: This attribute defaults to -1 (undefined).
negotiable Should the directory resource automatically create a NegotiatedResource? If this flag is true, the directory resource automatically creates negotiable resources on top of normal resources. Each time a new resource is added to the directory, the resource looks for a resource having the new child name with possibly different extensions. If it succeeds, either the resource found is already a negotiated resource, in which case the new child is added as one of its variant resources, or the negotiated resource must not already exist. The directory resource then creates it with only one variant, the new child resource. type: This attribute is an editable BooleanAttribute. default value: This attribute defaults to false.

The FileResource Class

This is the basic resource to process files. It allows you to export files and can be configured to handle the HTTP PUT method. The FileResource class inherits from HTTPResource and FilteredResource. The FileResource defines three attributes filename, putable, and filestamp, as shown in Table 25.3.

Table 25.3  Attributes of FileResource

AttributeDescription
filename This is the optional name of the file to be served by the file resource. By default, the file resource serves the file having the same name as the resource. You can define this attribute to modify the URL to file mapping. For example, you can serve the file foo.html through the name oof.html by setting the foo.html filename attribute to oof.html. type: This attribute is an editable FilenameAttribute. default value: This attribute is undefined.
putable Should the file resource support PUT requests? If this flag is true, the file resource object handles the HTTP PUT method by overwriting the resource's file with the new content. The old content is saved using the emacs backup convention (a ~ is appended to the original file name). Take care when enabling this feature. You'll probably want to use an authentication filter to ensure that only authorized users are allowed to change files on the server. type: This attribute is an editable BooleanAttribute.default value: This attribute defaults to false.
Filestamp This is the date on which the file resource last checked its consistency against the underlying physical file. type: This attribute is a computed DateAttribute which is noneditable.default value: This attribute defaults to -1 (undefined).

Installation and Setup of the Jigsaw HTTP Server

Jigsaw is an easy server to install and set up. If you don't already have the Jigsaw server running, the following information will help you get a server installed and running as painlessly as possible.

Start your favorite browser and go to URL

http://www.w3.org/pub/WWW/Jigsaw/#Getting.

Select jigsaw.zip for Microsoft Windows 95/NT or jigsaw.tar.gz for UNIX.

When the file has finished downloading, unzip or gunzip and un-tar, as needed. Both archives unpack into a directory structure starting at Jigsaw. The archive has long filenames so make sure you have an unzip that can handle this situation correctly.

In the following discussion, the term Windows refers to Microsoft Windows 95/NT. Similarly, UNIX refers to the UNIX operating system.

In this sample setup, unpack the Windows archive to D:\ and /usr/www in UNIX. Call this BASEDIR for short. Make sure to replace BASEDIR as appropriate for your setup. In this example, use D:\ or /usr/www instead of BASEDIR.

Now let the Java interpreter know where to find the Jigsaw classes.

On Windows, type the command:

SET CLASSPATH=BASEDIR\Jigsaw\classes\jigsaw.zip

And on UNIX, choose one of the following, depending on your shell:

SH: CLASSPATH=BASEDIR/Jigsaw/classes/jigsaw.zip ; export CLASSPATH

or

CSH: setenv CLASSPATH BASEDIR/Jigsaw/classes/jigsaw.zip.

You are now ready to run the server for the first time. On Windows, type the following command:

java w3c.jigsaw.http.httpd -host your-host.your-domain -root BASEDIR\Jigsaw\Jigsaw.

If you are running UNIX, type:

java w3c.jigsaw.http.httpd -host your-host.your-domain -root BASEDIR/Jigsaw/Jigsaw.

Replace your-host.your-domain with the host name and domain of your machine.

Jigsaw starts executing, and you should see one of the following:

In Windows:

loading properties from: d:\Jigsaw\Jigsaw\config\httpd.props
[httpd]: listening at:http://your-host.your-domain:9999

In UNIX:

loading properties from: /usr/WWW/Jigsaw/Jigsaw/config/httpd.props
[httpd]: listening at:http://your-host.your-domain:9999

Now start your favorite browser and go to URL

http://your-host.your-domain:9999.

Finally, read the configuration tutorial and other documentation that comes with the server. No configuration changes are needed to follow along with the examples in this chapter.

Note
If your server will be accessible by others, you'll want to use the section on protecting the Admin resource in the Jigsaw documentation.
(http://your-host.your-domain:9999/User/Tutorials/
configuration.html#authentication)

Caution
There is a security problem in the current version of Jigsaw. Make sure you understand the implications, especially if you are running UNIX.
As of version 1.0, Jigsaw does not give up its root privileges, so you may want to use another port such as 8080 or the default 9999, and run the server as a normal user. There are plans to add system calls to switch to a nonprivileged user in the next Jigsaw release.

Tip
Using the telnet program, you can verify that your server is working without having to access a browser. On UNIX, type telnet your-host.your-domain 9999 when you see:
Connected to your-host.your-domain
Escape character is "^]".
type HEAD / HTTP/1.0 and press Enter twice.
The server should return:
HTTP/1.0 200 OK
Content-Length: 701
Content-Type: text/html
Last-Modified: 25 May 1996 15:05:56 GMT
Server: Jigsaw/1.0a
Date: 22 Aug 1996 23:00:33 GMT
You can also start the Windows telnet program and select Connect Remote ystem. Enter the Host Name and replace the telnet Port with 9999 in the dialog box. Then type the line: HEAD / HTTP/1.0 and press Enter twice.

Adding Content to the Jigsaw Server

Now that you have the server running, you can add some content. By default, additional content is added to Jigsaw in the BASEDIR/Jigsaw/Jigsaw/WWW directory tree. Be sure you change your directory to the one listed above before continuing.

Obtain either example.zip or example.tar. Unzip or untar the archives as appropriate. This extracts a small collection of html and gif files under the que directory.

Now start your browser and go to HTTP://your-host.your-domain/que/. This brings up a directory-style listing of the files just extracted, as seen in Figure 25.1-not quite what you wanted, so now open the URL HTTP://your-host.your-domain/Admin/Editor/que.

Figure 25.1 : Results of opening http://your-host.Your-domain: 9999/que/.

Move on to the form now displayed and change the entry index: to index.html. Then click the OK button at the bottom of the page as shown in Figure 25.2. Reopen the URL HTTP://your-host.your-domain/que/. This time you see the content of index.html shown in Figure 25.3 instead of the directory listing.

Figure 25.2 : Form to add index.html as the index for the que resource.

Figure 25.3 : Browser rendered contents of que/index.html.

Note
You may need to clear your browser's cache so the URL is displayed correctly.

Finally, add an existing Java class to your que resource.

Open URL HTTP://your-host.your-domain/Admin/Editor/que and select the AddingResources link at the bottom of the page. Enter Memory in the name: field. Enter w3c.jigsaw.status.GcStat in the class: field and press the OK button as seen in Figure 25.4.

Figure 25.4 : Form to add a Java resource to the server namespace.

Opening the URL HTTP://your-host.your-domain/que/Memory should now show the memory status for your server, as seen in Figure 25.5.

Figure 25.5 : Results of accessing the Java resource added as Que/Memory .

As you can see, it is easy to add existing document trees to the server and specify a start page for the tree.

Extending the Server with Java

You can now get down to writing your own Java classes to extend your server. Start off with something simple.

The first step in writing your resource is choosing a super class, as follows:

For this example, use HTTPResource. The only other initial decision you need to make is the package name for your new resource. Jigsaw does not impose any restrictions on the name you assign your package as long as the Java interpreter can find it via the CLASSPATH environment variable.

Caution
Security Note: Keep in mind the possibility of someone adding code to your server via CLASSPATH if it points to a world/group writable directory.

Unzip or untar the classes.zip or classes.tar file to BASEDIR/Jigsaw. This creates files under BASEDIR/Jigsaw/que/que/examples.

You now know enough to create the BASEDIR/Jigsaw/que/que/examples/HelloJigsaw.java (refer to Listing 25.1) source file, as follows:

package que.examples
import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;
import w3c.jigsaw.html.*;
public class HelloJigsaw extends HTTPResource {

Now you need to decide on the attributes for your new resource. To keep things simple, only deal with the message text returned by your resource.

// message attribute index
protected static int ATTR_MESSAGE = -1 ;

static {
   Attribute attrib  = null ;
   Class   HelloClass = null ;
         
   try {
       HelloClass = Class.forName("que.examples.HelloJigsaw");
   } catch (Exception ex) {
       ex.printStackTrace() ;
       System.exit(1) ;
   }

After declaring your attributes, register them with the AttributeRegistery. The registry keeps track of all the attributes of all resource classes. For each class the registry knows about, it maintains an ordered list of the attributes declared by the class.

The attribute registry returns an index for each attribute that is registered. You can use the index as a parameter to the setValue and getValue methods of the AttributeHolder class to obtain the attribute value.

         // register our message attribute:
         attrib = new StringAttribute("message", "Hello Jigsaw World!",
 Attribute.EDITABLE);
         ATTR_MESSAGE = AttributeRegistery.registerAttribute
 (HelloClass, attrib) ;
     }

Now, implement the behavior of your resource. The only HTTP method this resource allows is the GET method. Generate a reply at each invocation of this resource using the HtmlGenerator class provided by Jigsaw.

     // Print our message in response to the HTTP GET request

   public Reply get(Request request)
    throws HTTPException {
   // create HTML generator and fill in titles:
       HtmlGenerator gen = new HtmlGenerator("HelloJigsaw");
       gen.append("<h1>Our first Jigsaw extension demo</h1>");
       // print our message:
       gen.append("<p>"+getValue(ATTR_MESSAGE, null));

       // finish off the reply
     Reply rep = request.makeReply(HTTP.OK) ;
     rep.setStream(gen) ;
     return rep ;
  }
}

Listing 25.1  HelloJigsaw.java-A Class to Respond to the HTTP GET Method
package que.examples ;

import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;
import w3c.jigsaw.html.*;

public class HelloJigsaw extends HTTPResource {
 // message attribute index
 protected static int ATTR_MESSAGE = -1;

 static {
  Attribute attrib  = null;
  Class   HelloClass = null;
         
  try {
   HelloClass = Class.forName("que.examples.HelloJigsaw");
  } catch (Exception ex) {
   ex.printStackTrace();
   System.exit(1);
  }
  // register our message attribute:
  attrib = new StringAttribute("message", "Hello Jigsaw World!", Attribute.EDITABLE);
  ATTR_MESSAGE = AttributeRegistery.registerAttribute(HelloClass, attrib);
 }

 // Print our message in response to the HTTP GET request

 public Reply get(Request request)
  throws HTTPException {
   // create HTML generator and fill in titles:
   HtmlGenerator gen = new HtmlGenerator("HelloJigsaw");
   gen.append("<h1>Our first Jigsaw extension demo</h1>");
   // print our message:
   gen.append("<p>"+getValue(ATTR_MESSAGE, null));

 
   // finish off the reply
   Reply rep = request.makeReply(HTTP.OK) ;
   rep.setStream(gen);
   return rep;
 }

}

Now add your new resource to the server. First, stop the server and update the CLASSPATH environment variable so the server can find your new class.

Under Windows:

SET CLASSPATH=BASEDIR\Jigsaw\classes\jigsaw.zip;BASEDIR\Jigsaw\que

And on UNIX:

SH: CLASSPATH=BASEDIR/Jigsaw/classes/jigsaw.zip:BASEDIR/Jigsaw/que ;
Âexport CLASSPATH

or

CSH: setenv CLASSPATH BASEDIR/Jigsaw/classes/jigsaw.zip:BASEDIR/Jigsaw/que.

Restart the server.

Open the URL http://your-host.your-domain:9999/Admin/Editor/que.
Select the AddingResources link at the bottom of the page.
Type Hello in the name: field.
Type que.examples.HelloJigsaw in the class: field and click OK as shown in Figure 25.6.

Figure 25.6 : Form to add your Hello Java resource to the server's namespace.

If Jigsaw returns the error message "The field class has an incorrect value," verify that the class name was entered correctly. If the class value is correct, check the CLASSPATH variable in your environment.

You are returned to the Admin/Editor/que screen if the change was successful. Opening URL http://your-host.your-domain:9999/que/Hello will execute the new class returning the text "Hello Jigsaw World!"

Writing Resource Filters in Java

As most resource classes provided by Jigsaw descend from FilteredResource, they inherit a set of filters that are sub-classes of ResourceFilter, providing a callback twice during resource processing. Now create a class to use this function (see Listing 25.2).

package que.examples.filter;

import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;

public class CountingFilter extends ResourceFilter {
   // counter attribute index.
  protected static int ATTR_COUNTER = -1 ;

  static {
    Attribute counterattrib  = null ;
    Class   CountingClass = null ;

    try {
      CountingClass = Class.forName("que.examples.filter.CountingFilter") ;
    } catch (Exception ex) {
      ex.printStackTrace() ;
      System.exit(1) ;
    }

Now create an attribute for your class, an integer. This attribute is persistent so this is all you need to do to keep a filtered count for the lifetime of your server.

  counterattrib = new IntegerAttribute("counter"
              , new Integer(0)
              , Attribute.EDITABLE) ;
  ATTR_COUNTER = AttributeRegistery.registerAttribute(CountingClass, counterattrib);
}

This method is called during resource lookup with the HTTP request as the parameter.

public synchronized int ingoingFilter(Request request) {
   // get our counter attribute
  int i = getInt (ATTR_COUNTER, 0) ;
  // put it back plus one
  setInt(ATTR_COUNTER, i+1) ;

Returning DontCallOutgoing informs the target filtered resource that you have done your work and your outgoingFilter method does not need to be called after resource processing. Also, you do not need to declare an outgoingFilter method because your superclass provides an empty method.

    return DontCallOutgoing ;
  }
}

Listing 25.2 shows the CountingFilter class.


Listing 25.2  CountingFilter.java-Count Number of "Hits" on Filtered Resource
package que.examples.filter;

import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;

public class CountingFilter extends ResourceFilter {
 // counter attribute index.
 protected static int ATTR_COUNTER = -1 ;

 static {
  Attribute counterattrib  = null ;
  Class   CountingClass = null ;

  try {
   CountingClass = Class.forName("que.examples.filter.CountingFilter") ;
  } catch (Exception ex) {
   ex.printStackTrace() ;
   System.exit(1) ;
  }

  counterattrib = new IntegerAttribute("counter"
      , new Integer(0)
      , Attribute.EDITABLE) ;
  ATTR_COUNTER = AttributeRegistery.registerAttribute(CountingClass, counterattrib) ;
 }

 public synchronized int ingoingFilter(Request request) {
  // get our counter attribute
  int i = getInt (ATTR_COUNTER, 0) ;
  // put it back plus one
  setInt(ATTR_COUNTER, i+1) ;
  return DontCallOutgoing ;
 }
}

Now plug your filter into the server. If you followed along with the previous section, your server does not need any changes. If not, go back and update your CLASSPATH environment variable and restart the server as detailed in the previous section.

Open URL http://your-host.your-domain:9999/Admin/Editor/que to edit the properties of the que directory resource. Follow the AddFilter link at the bottom of the page.

Enter que.examples.filter.CountingFilter in the Filter's class: field and click OK, as shown in Figure 25.7. This creates two additional links at the bottom of the que.examples.filter.CountingFilter page.

Figure 25.7 : Form to add your Java filter to the server's namespace.

These new links access the properties of the filter. Here you see a single attribute counter that is initially set to 0. You do not need to enter anything in the identifier: field on this page.

A link to ShadowByque.examples.filter.CountingFilter is also added to the page. This takes you to attributes shadowed by que.examples.filter.CountingFilter. Nothing needs to be changed there.

Now when the resource que is requested from your server, the ingoingFilter method of CountingFilter will be called incrementing the integer attribute counter. You can reload the filters attribute page to view the counter as shown in Figure 25.8.

Figure 25.8 : Viewing the value of your counter filter attribute.

Note
Due to a bug in version 1.0 of Jigsaw, this field display is not updated. You need to restart the server via /Admin/PropertiesEditor for the updates to be viewable.

Handling Forms and the POST Method in Java

Complete your look inside the Jigsaw server by using a class to handle the HTTP POST method (refer to Listing 25.3).

package que.examples.postable;

import w3c.jigsaw.forms.*;
import w3c.jigsaw.html.*;
import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;

import java.util.*;


public class JigsawPost extends PostableResource
{

 protected static int ATTR_NAME   = -1 ;

 protected final static String NAME   = "Name:";

Here you could place any number of form elements as attributes. This code is like the other extension examples you covered in the previous two sections.

static {
 Attribute attrib   = null ;
 Class   JPostClass = null ;

try
 {
    JPostClass = Class.forName("que.examples.postable.JigsawPost") ;
  } catch (Exception ex) {
    ex.printStackTrace() ;
    System.exit(1) ;
  }
  // register our attribute(s)
  attrib  = new StringAttribute(NAME , "", Attribute.EDITABLE) ;
  ATTR_NAME = AttributeRegistery.registerAttribute(JPostClass, attrib) ;
}


// method to handle data from POST request
public Reply handle (Request request, URLDecoder data)
 throws HTTPException 
{

Here you do the work of handling the data resulting from the POST method. Now you could pick up form data, validate it, and perhaps place it in a database or send the data using a Java interface to sendmail. For this example, print out the posted data. This gives you a nice debugging resource.

  // print out the variables we received
  // a handy object to have around when testing postable forms
  Enumeration  en = data.keys() ;
  HtmlGenerator gen = new HtmlGenerator ("POST method decoded values") ;
  gen.append ("<p>List of variables and corresponding values:</p><ul>") ;
  while ( en.hasMoreElements () ) {
   String name = (String) en.nextElement() ;
   gen.append ("<li><em>"
        + name+"</em> = <b>"
        + data.getValue(name)
        + "</b></li>");
  }

  gen.append ("</ul>") ;
  Reply reply = request.makeReply(HTTP.OK) ;
  reply.setStream (gen) ;
  return reply ;
 }


}

Adding this postable object to the server is like the examples in the previous sections. Open URL http://your-host.your-domain/Admin/Editor/que. Select the Adding-Resources link. Enter PostTest for the name: field and que.examples.postable.JigsawPost for the class: field. Press OK to add the resource as shown in Figure 25.9.

Figure 25.9 : Form adding your PostTest Java resource to the server's namespace.

If you open the URL http://your-host.your-domain:9999/que/PostTest, Jigsaw returns the error message "Document not found. The document /que/PostTest is indexed but not available." To test the object, use the following URL:

http://your-host.your-domain:9999/que/PostTest?name=dave;

which returns the output shown in Figure 25.10.

Figure 25.10: Result of accessing the PostTest resource.

Normally, to use a resource like this you would use HTML code such as:

<FORM METHOD="POST" ACTION="/que/PostTest">Name:
<INPUT TYPE="text" NAME="name" MAXLENGTH=32><br>
<INPUT TYPE="reset" VALUE="Reset">
<INPUT TYPE="submit" VALUE="Ok">

An sample form can be viewed with the URL http://your-host.your-domain:9999/que/testform.html seen in Figure 25.11.

Figure 25.11: Example of the Post Test HTML form.

Listing 25.3 shows the JigsawPost class.


Listing 25.3  JigsawPost.java-Class to Implement HTTP POST Method
package que.examples.postable;

import w3c.jigsaw.forms.*;
import w3c.jigsaw.html.*;
import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;

import java.util.*;


public class JigsawPost extends PostableResource
{

 protected static int ATTR_NAME   = -1 ;

 protected final static String NAME   = "Name:";

 static {
  Attribute attrib   = null ;
  Class   JPostClass = null ;

  try
   {
     JPostClass = Class.forName("que.examples.postable.JigsawPost") ;
   } catch (Exception ex) {
     ex.printStackTrace() ;
     System.exit(1) ;
   }
   // register our attribute(s)
   attrib  = new StringAttribute(NAME , "", Attribute.EDITABLE) ;
   ATTR_NAME = AttributeRegistery.registerAttribute(JPostClass, attrib) ;
 }


 // method to handle data from POST request
 public Reply handle (Request request, URLDecoder data)
  throws HTTPException 
 {

  // print out the variables we received
  // a handy object to have around when testing postable forms
  Enumeration  en = data.keys() ;
  HtmlGenerator gen = new HtmlGenerator ("POST method decoded values") ;
  gen.append ("<p>List of variables and corresponding values:</p><ul>") ;
  while ( en.hasMoreElements () ) {
   String name = (String) en.nextElement() ;
   gen.append ("<li><em>"
        + name+"</em> = <b>"
        + data.getValue(name)
        + "</b></li>");
  }

  gen.append ("</ul>") ;
  Reply reply = request.makeReply(HTTP.OK) ;
  reply.setStream (gen) ;
  return reply ;
 }


}

You should now know enough about Jigsaw to add exciting new content to the World Wide Web. Drop me a note and tell me about your projects. My e-mail address is dave@daves.net.