W3C logo
Jigsaw

Jigsaw
Frame tutorial


Jigsaw Home / Documentation Overview / Tutorials

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:

  1. writing the frame class,
  2. installing and configuring it.

Writing the frame class

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

  1. What will be its super class
  2. In what package should it go
  3. What attribute should it define
  4. What method should it redefine

Picking a super class

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.

Selecting a package

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 {

}

Defining the attributes

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);
    }
}

Redefining some methods

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 ;
    }
}

Note:

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.

Installing the frame

After reading the Resource configuration tutorial you will be able to install the FancyFrame. Here is what I get with my configuration:

FancyFrame associated with a FileResource

FileResource

FancyFrame associated with a DirectoryResource

DirectoryResource

FancyFrame associated with a FramedResource

FramedResource



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:

  1. You can start by going through the code of the HTTPFrame , which is more complex then our FancyFrame. Every frame relative to the HTTP protocol must be a subclass of it.
  2. You can then continue by browsing the RelocateFrame, which emit an HTTP redirect reply.
  3. If you still have more courage, then try reading the NegotiatedFrame, which manage content negotiation. There is a significant increase in complexity here.
  4. Take a look at the Sample code page.

Enjoy !