Resource tutorial.

# Writing a new resource class

This tutorial explains you how to write a new resource, by walking through a complete example. It is assumed that you are familiar with Jigsaw architecture, and that you have understand the configuration tutorial.

The resource we will write here, will display a message along with a set of customizable request headers. The tutorial will go through the following steps:

- Writing the resource class,
- Installing it and configuring it.

## Writing the resource class

Before actually writing a new resource, some decisions must be made about:

- What will be it super-class
- In what package should it go
- What attribute should it define
- Being smart with caches

### Picking a super-class

Deciding for the super-class of your resource is a pretty simple process right now. Here are the rule of thumbs:

- If your resource is to wrap a directory (i.e. it will contain child resource), then a good bet is to sub-class the DirectoryResource, which provides you with the children store management.
- If your resource wraps some file (i.e. it serves files), then you probably want to sub-class the FileResource class.
- If your resource is to handle forms, then you definetly want to pick a sub-class of PostableResource as your super-class. This will give you the form arguments decoding for free.
- Finally, if you want to write a fancy dynamic resource (like the ThreadStat one, for example), then you will probably fallback by sub-classing the HTTPResource class.

Given these short rules, it should be obvious that for our sample resource, what we want to do is to subclass the HTTPResource. So right now, we can start writing the following piece of code (we will keep in bold the additional code we add as we walk through the example):

    import w3c.www.http.*;
    import w3c.jigsaw.http.*;
    import w3c.jigsaw.resources.*;
    import w3c.tools.store.*;
    public class FancyResource extends HTTPResource {

    }

Note that we don't know yet were to put this file until we have selected an appropriate package for our resource.

### Selecting a package

There is no particular problem with regard to the package your resource belong to: Jigsaw impose no constraint on this. The only thing you should be aware of is your CLASSPATH environment variable. This variable setting is particularly crucial in Jigsaw since it may impact its security: you don't want anyone to be able to plug new resource classes in the server !

For our sample resource, we can create a new package, let's call it `tutorial`, under the Jigsaw classes directory. We want this package to be under the `w3c.jigsaw` package. We can now create the appropriate directory (`src/classes/w3c/jigsaw/tutorial`), and write in it the following `FancyResource.java` file:

    package w3c.jigsaw.tutorials ;

    import w3c.www.http.*;
    import w3c.jigsaw.http.*;
    import w3c.jigsaw.resources.*;
    import w3c.tools.store.*;

    public class FancyResource extends HTTPResource {

    }

### Defining the attributes

The next thing we have to figure out, is the list of attributes for our new resource. The HTTPResource already defines a number of attributes (see the reference manual). Defining the set of attributes of a resource also defines the way the resource will be configured (since a resource is configured by editing its attribute values). Here, we want to be able to configure:

- The message that will be emited by the resource
- The name of the request headers that the resource should display

The message emited by the resource can be described as an editable StringAttribute, which defaults to Hello. The name of the request headers to dump can be encoded as a StringArrayAttribute, each entry in the array giving the name of a header. If this last attribute is undefined, then we will emit all of the request headers in our reply.

Now that we now the attributes our resource is to have, we should declare them to the AttributeRegistry. This Registry keeps track of all the attributes of all resource classes. For each class it knows of, it maintains an ordered list of the attribute it defines. The fact that this list is ordered is important, since it allows for fast attribute value access (through a simple indirection in the attribute value array of each resource instance). Attribute declaration should be done at class initialization time, so we introduce a static statement in the class, whose purpose is to declare our attributes:

    package w3c.jigsaw.tutorials ;

    import w3c.www.http.*;
    import w3c.jigsaw.http.*;
    import w3c.jigsaw.resources.*;
    import w3c.tools.store.*;

    public class FancyResource extends HTTPResource {

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

    	static {
    		Attribute a   = null ;
    		Class     cls = null ;

    		try {
    			cls = Class.forName("w3c.jigsaw.tutorials.FancyResource");
    		} catch (Exception ex) {
    			ex.printStackTrace() ;
    			System.exit(1) ;
    		}
    		// Register the message attribute:
    		a = new StringAttribute("message", "Hello", Attribute.EDITABLE);
    		ATTR_MESSAGE = AttributeRegistry.registerAttribute(cls, a) ;
    		// Register the headers attribute:
    		a = new StringArrayAttribute("headers", null, Attribute.EDITABLE) ;
    		ATTR_HEADERS = AttributeRegistry.registerAttribute(cls, a) ;
    	}

    }

Notice how the attribute Registry returns back an attribute index for each of the attribute we register. This index can then be used as a parameter to the `setValue` and `getValue` methods of AttributeHolder instances, to describe the attribute they should act on.

At this point, we have declared the set of attributes that our resource defines, the attribute Registry knows about it, we can now focus on the actual behavior of the resource. The only HTTP method that our resource will support is the `GET` method, which will synthetise a reply on the fly for each specific request. Jigsaw comes with a simple HtmlGenerator class for generating HTML that we want to use for this purpose. The actual implementation of the method is the following:

    package w3c.jigsaw.tutorials ;

    import w3c.www.http.*;
    import w3c.jigsaw.http.*;
    import w3c.jigsaw.resources.*;
    import w3c.tool.store.*;

    import w3c.jigsaw.html.* ;

    public class FancyResource extends HTTPResource {

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

    	static {
    		Attribute a   = null ;
    		Class     cls = null ;

    		try {
    			cls = Class.forName("w3c.jigsaw.tutorials.FancyResource");
    		} catch (Exception ex) {
    			ex.printStackTrace() ;
    			System.exit(1) ;
    		}
    		// Register the message attribute:
    		a = new StringAttribute("message", "Hello", Attribute.EDITABLE);
    		ATTR_MESSAGE = AttributeRegistry.registerAttribute(cls, a) ;
    		// Register the headers attribute:
    		a = new StringArrayAttribute("headers", null, Attribute.EDITABLE) ;
    		ATTR_HEADERS = AttributeRegistry.registerAttribute(cls, a) ;
    	}

    	/**
    	 * Display the resource message with the request headers.
    	 * @param request The request to handle.
    	 * @exception HTTPException If processing the request failed.
    	 */

    	public Reply get(Request request)
    		throws HTTPException
    	{
    		// Create the HTML generator, and set titles:
    		HtmlGenerator g = new HtmlGenerator("FancyResource");
    		g.append("<h1>FancyResource output</h1>");
    		// Emit the message:
    		g.append("<p>"+getValue(ATTR_MESSAGE, null));
    		// Now emit the requested headers:
    		String headers[] = (String[]) getValue(ATTR_HEADERS, null) ;
    		if ( headers != null ) {
    			g.append("<hr><h2>Request headers:</h2><dl>");
    			for (int i = 0 ; i < headers.length ; i++) {
    				g.append("<dt>"+headers[i]+"</dt><dd>");
    				String value = request.getValue(headers[i]);
    				g.append((value == null)
    					 ? "<em>undefined</em>"
    					 : value) ;
    			}
    		}
    		Reply reply = createDefaultReply(request, HTTP.OK) ;
    		reply.setStream(g) ;
    		return reply ;
    	}

    }

We are done, you can now compile the above code, which should produce a `FancyResource.class` file, the next section will explain how to install it in the information space. Before switching to this, it is worth pointing out that the instances of our new resource class will be made persistent by the Jigsaw runtime: this means that once plugged into the resource space, a new instance of the FancyResource class will keep its attribute values across Jigsaw invocations.

### Being smart with caches

Before continuing into the installation of that new resources, we would like to look into caching issues. As written above, the output generated by our resource doesn't say nothing about wether it's cachable or not. Under these circumstances, most existing caches will try to cache the resource content.

Although what we really want is to prevent any sort of caching for that particular resource, since its output depends on the request it answers too. To handle this situation, we can use the newly defined request headers in HTTP/1.1. What we really want is to tell any caches between our resource and the client to keep out of the way. To do this, we need to set the `no-store` cache control directive, defined in HTTP/1.1.

This can be done by redefining the `createDefaultReply` method of our superclass in the following way:

    package w3c.jigsaw.tutorials ;

    import w3c.www.http.*;
    import w3c.jigsaw.http.*;
    import w3c.tools.store.*;
    import w3c.jigsaw.resources.*.*;

    import w3c.jigsaw.html.* ;

    public class FancyResource extends HTTPResource {
    	...

        public Reply createDefaultReply(Request request, int status) {
            Reply reply = super.createDefaultReply(request, status);
            reply.setNoStore(true);
            // Be friendly to HTTP/1.0 caches too:
            reply.addPragma("no-cache");
            return reply;
        }

    }

This set the `no-store` cache control directive, and it also set the `no-cache` pragma, in case there is an HTTP/1.0 proxy between our resource and the client.

### Installing the resource

You are not supposed to have compiled the fancy resource class. What we want to do here, is actually using it in our exported space. For the sake of this example, we will just attach an instance of the fancy resource to Jigsaw documentation directory (the `/User` directory). Don't be afraid, you will also learn how to remove it from there by the end of this tutorial).

As you might have guess after reading the configuration tutorial, what we are going to do here, is bring up the generic resource editor on the `/User` directory resource. Point your favorite browser to `/Admin/Editor/User`, and follow the link to AddingResource. This shows up a form prompting us for the resource name (i.e. the name of the resource in the URL space), and the resource class. Let's call our resource `fancy`, and the class, of course, is `w3c.jigsaw.tutorials.FancyResource`. We press the OK button to create the resource, then we follow the ExistingResources link. This link pops up the list of resources of the `/User` directory, we click on the `fancy` one. This brings up the editor for the attribute value of our fancy resource. We are mostly interested by our specific attributes: `message` and `headers`. Let's have fun here, first set the message to whatever you think is appropriate, then type in the name of the request header you want the resource to display (lower case, one per line). In my configuration I have set the message to Testing the fancy resource, and I have selected the `user-agent` and `accept` headers. Press the OK button: we are all set, let's test this by visiting the `/User/fancy` resource. Here is what I get with my configuration:

### FancyResource output Testing the fancy resource ### Request headers: user-agent Mozilla/2.0 (X11; I; SunOS 5.3 sun4m) accept image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

The example we have been walking through is probably one of the simplest one, however, by now, you should be able to read and understand the basic resource classes provided by Jigsaw. I would recommend reading them in the following order:

- You can start by going through the code of the FileResource , which is a little more complex then our fancy resource, but not much.
- You can then continue by browsing the PostableResource, which is the one that you are most likely to use in real life. This should allow you to write resources that handles the `POST` method.
- If you still have more courage, then try reading the DirectoryResource. There is a significant increase in complexity here. since the directory resource manages a children resource store. However, once you have understood the code of this resource, then Jigsaw doesn't have much less you don't know about.

Enjoy !

Jigsaw Team
$Id: resource.html,v 1.14 1997/07/31 08:26:40 ylafon Exp $