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:
Before actually writing a new resource, some decisions must be made about:
Deciding for the super-class of your resource is a pretty simple process right now. Here are the rule of thumbs:
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.
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 { } |
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 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.
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.
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 outputTesting the fancy resource
|
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:
POST
method.
Enjoy !
Jigsaw Team
$Id: resource.html,v 1.14 1997/07/31 08:26:40 ylafon Exp $