This tutorial explains you how to write a new frame, 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 frame we will write here will display a message describing its attribute and its associated resource. The tutorial will go through the following steps:
Before actually writing a new frame, some decisions must be made about:
Deciding for the super class of your frame 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 frame, what we want to do is subclass the HTTPFrame. 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 java.util.*; import org.w3c.tools.resources.*; import org.w3c.jigsaw.frames.*; import org.w3c.jigsaw.html.*; import org.w3c.jigsaw.http.* ; import org.w3c.www.http.* ; public class FancyFrame extends HTTPFrame { }
Note that we don't know yet were to put this file until we have selected an appropriate package for our frame.
There is no particular problem with regard to the package your frame 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 frame, 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 FancyFrame.java file:
package org.w3c.jigsaw.tutorials; import java.util.*; import org.w3c.tools.resources.*; import org.w3c.jigsaw.frames.*; import org.w3c.jigsaw.html.*; import org.w3c.jigsaw.http.* ; import org.w3c.www.http.* ; public class FancyFrame extends HTTPFrame { }
The next thing we have to figure out, is the list of attributes for our new frame. The HTTPFrame already defines a number of attributes (see the reference manual). Defining the set of attributes of a frame also defines the way the frame will be configured (since a frame is configured by editing its attribute values). Here, we want to be able to configure the message that will be emitted by the frame.
The message emitted by the frame can be described as an editable StringAttribute, which defaults to Hello.
Now that we now the attribute our frame is to have, we should declare it 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 frame 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 attribute:
package org.w3c.jigsaw.tutorials; import java.util.*; import org.w3c.tools.resources.*; import org.w3c.jigsaw.frames.*; import org.w3c.jigsaw.html.*; import org.w3c.jigsaw.http.* ; import org.w3c.www.http.* ; public class FancyFrame extends HTTPFrame { /** * Attribute index - Message to display */ protected static int ATTR_MESSAGE = -1 ; static { Attribute a = null ; Class cls = null ; try { cls = Class.forName("org.w3c.jigsaw.tutorials.FancyFrame"); } catch (Exception ex) { ex.printStackTrace() ; System.exit(1) ; } // The message attribute a = new StringAttribute("message", "Hello", Attribute.EDITABLE) ; ATTR_MESSAGE = AttributeRegistry.registerAttribute(cls, a) ; } /** * Get the message. * @return A String instance. */ public String getMessage() { return getString(ATTR_MESSAGE, null); } }
At this point, we have declared the set of attributes that our frame defines,
the attribute Registry knows about it, we can now focus on the actual behavior
of the frame. The only HTTP method that our frame will redefine is the GET
method, which will synthesize 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. Our FancyFrame
could be associated with many kinds of resources,
FileResource,
DirectoryResource,
any subclass of
FramedResource
or FramedResource itself.
In this particular case, we want to deal with all these resources, so we
have to redefine the followings method of
HTTPFrame:
The actual implementation of these methods is the following:
package org.w3c.jigsaw.tutorials; import java.util.*; import org.w3c.tools.resources.*; import org.w3c.jigsaw.frames.*; import org.w3c.jigsaw.html.*; import org.w3c.jigsaw.http.* ; import org.w3c.www.http.* ; public class FancyFrame extends HTTPFrame { /** * Attribute index - Message to display */ protected static int ATTR_MESSAGE = -1 ; static { Attribute a = null ; Class cls = null ; try { cls = Class.forName("org.w3c.jigsaw.tutorials.FancyFrame"); } catch (Exception ex) { ex.printStackTrace() ; System.exit(1) ; } // The message attribute a = new StringAttribute("message", "Hello", Attribute.EDITABLE) ; ATTR_MESSAGE = AttributeRegistry.registerAttribute(cls, a) ; } /** * Get the message. * @return A String instance. */ public String getMessage() { return getString(ATTR_MESSAGE, null); } /** * Display the Frame message and some attributes of our * associated FileResource. This method is called only if * our associated resource *is* a FileResource. * @param request The request to handle. * @return A Reply instance. * @exception ProtocolException if processing the request failed * @exception NotAProtocolException if an internal error occurs */ protected Reply getFileResource(Request request) throws ProtocolException, NotAProtocolException { // get our associated FileResource FileResource fres = getFileResource(); // Create the HTML generator, and set titles: HtmlGenerator g = new HtmlGenerator("FancyFrame"); g.append("<h1>FancyFrame output</h1>"); // emit the message g.append("<p>",getMessage(),"</p>"); // display information about our FileResource g.append("<h2> FileResource associated : </h2>"); g.append("<ul><li>Identifier : ",fres.getIdentifier()); g.append("<li>File : "+fres.getFile()); g.append("<li>Last Modified Time : ", new Date(fres.getLastModified()).toString(), "</ul>"); // now emit the reply Reply reply = createDefaultReply(request, HTTP.OK) ; reply.setStream(g) ; return reply ; } /** * Display the Frame message and some attributes of our * associated DirectoryResource. This method is called only if * our associated resource *is* a DirectoryResource. * @param request The request to handle. * @return A Reply instance. * @exception ProtocolException if processing the request failed * @exception NotAProtocolException if an internal error occurs */ protected Reply getDirectoryResource(Request request) throws ProtocolException, NotAProtocolException { // get our associated DirectoryResource DirectoryResource dres = getDirectoryResource(); // Create the HTML generator, and set titles: HtmlGenerator g = new HtmlGenerator("FancyFrame"); g.append("<h1>FancyFrame output</h1>"); // emit the message g.append("<p>",getMessage(),"</p>"); // display information about our DirectoryResource g.append("<h2> DirectoryResource associated : </h2>"); g.append("<ul><li>Identifier : ",dres.getIdentifier()); g.append("<li>Directory : "+dres.getDirectory()); g.append("<li>Last Modified Time : ", new Date(dres.getLastModified()).toString(), "</ul>"); // now emit the reply Reply reply = createDefaultReply(request, HTTP.OK) ; reply.setStream(g) ; return reply ; } /** * Display the Frame message and some attributes of our * associated Resource. This method is called if the associated * resource has been registered with <strong>registerOtherResource</strong> * or if it's not a usual resource (FileResource, DirectoryResource) * @param request The request to handle. * @return A Reply instance. * @exception ProtocolException if processing the request failed * @exception NotAProtocolException if an internal error occurs */ protected Reply getOtherResource(Request request) throws ProtocolException, NotAProtocolException { // get our associated Resource FramedResource res = getResource(); // Create the HTML generator, and set titles: HtmlGenerator g = new HtmlGenerator("FancyFrame"); g.append("<h1>FancyFrame output</h1>"); // emit the message g.append("<p>",getMessage(),"</p>"); // display information about our Resource g.append("<h2> Resource associated : </h2>"); g.append("<ul><li>Identifier : ",res.getIdentifier()); g.append("<li>Last Modified Time : ", new Date(res.getLastModified()).toString(), "</ul>"); // now emit the reply Reply reply = createDefaultReply(request, HTTP.OK) ; reply.setStream(g) ; return reply ; } }
Sometimes we don't need to know what kind of resource is associated with our frame, or we are sure to be associated with a resource which is not a FileResource neither a DirectoryResource. In that case we could redefine the following method like this:
/** * register our associated resource as an "other" resource. */ public void registerResource(FramedResource resource) { super.registerOtherResource(resource); }
So, we just have to redefine getOtherResource.
After reading the Resource configuration tutorial you will be able to install the FancyFrame. Here is what I get with my configuration:
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
Frame classes provided by Jigsaw. I would recommend reading them in the following
order:
Enjoy !