W3C logo
Jigsaw

Jigsaw
Resource's filter tutorial


Jigsaw Home / Documentation Overview / Tutorials

This tutorial assumes that your are familiar with Jigsaw architecture, and that you have read both the configuration and the resource tutorials. It will explain you the last major concept of Jigsaw you should be aware of: resource filters.

Note: In Jigsaw2.0, filters must be attached to frames, NOT resources!

As was said in the architectural overview of Jigsaw, each HTTP request ends up performed by some target resource and frame instance. For the sake of simplicity, we didn't mentioned at that time, that frame classes provided with the Jigsaw server inherits from the FramedResource class. All instances of this class are able to manage a set of frames that can be filters: these filters, which are to be instances of sub-classes of ResourceFilter, are called-back twice during request processing:

A resource filter is itself a resource: this means, in particular, that it is described - like all other resources - by a Java class, and a set of attributes. It also means that it can be pickled/unpickled, etc.

The remaining of this tutorial will walk through the code of the CounterFilter. This filter just counts the number of hits to its target resource. Before going any further, you should again make sure you have understand the resource tutorial. This tutorial has two sections: the first one will describe our filter's code, and the second one will explain how to attach it to a frame of the target resource.

The CounterFilter class

Its my hope that you will be amazed by how easy this filter is to code. As for writing new resource classes, the first thing we need to is to define the set of attributes that our filter will handle. In the case of a simple counter filter, the only attribute we need is simply the counter itself. Assuming we want our class to be in the org.w3c.jigsaw.filters package, we start by writing the following piece of code:
// CounterFilter.java
// $Id: writing-filters.html,v 1.5 2000/03/10 16:49:16 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.filters;

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

/**
 * Count the number of hits to the target.
 * This resource maintains the number of hits to some target resource, as
 * one of its persistent attribute.
 * It will decorate the request on the way in with a fake field
 * <code>org.w3c.jigsaw.filters.CounterFilter.count</code>, that will
 * hold the current hit counts for the target resource to use.
 */

public class CounterFilter extends ResourceFilter {
    /**
     * The name of the piece if state that receives the hit count value.
     * To get to the hit-count, use the <code>getState</code> method of 
     * Request, with the following key.
     */
    public static final 
        String STATE_COUNT = "org.w3c.jigsaw.filters.CounterFilter.count";

    /**
     * Attribute index - The counter attribute.
     */
    protected static int ATTR_COUNTER = -1 ;

    static {
        Attribute a   = null ;
        Class     clsnull ;
        
        try {
            cls = Class.forName("org.w3c.jigsaw.filters.CounterFilter") ;
        } catch (Exception ex) {
            ex.printStackTrace() ;
            System.exit(1) ;
        }
        // Declare the counter attribute
        a = new IntegerAttribute("counter"
                                 , new Integer(0)
                                 , Attribute.EDITABLE) ;
        ATTR_COUNTER = AttributeRegistry.registerAttribute(cls, a) ;
    }
}
This code does the following: it starts by declaring our resource filter class, and specify (through the static statement) its counter attribute, which is an editable integer attribute, whose default value is 0. We register this attribute to the AttributeRegistry, and get back the token for accessing the attribute. If some of this seems unfamiliar, then refer to the resource tutorial.

We can now implement the ingoingFilter method of our filter, which is as simple as you might expect:

// CounterFilter.java
// $Id: writing-filters.html,v 1.5 2000/03/10 16:49:16 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.filters;

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

/**
 * Count the number of hits to the target.
 * This resource maintains the number of hits to some target resource, as
 * one of its persistent attribute.
 * It will decorate the request on the way in with a fake field
 * <code>org.w3c.jigsaw.filters.CounterFilter.count</code>, that will
 * hold the current hit counts for the target resource to use.
 */

public class CounterFilter extends ResourceFilter {
    /**
     * The name of the piece if state that receives the hit count value.
     * To get to the hit-count, use the <code>getState</code> method of 
     * Request, with the following key.
     */
    public static final 
        String STATE_COUNT = "org.w3c.jigsaw.filters.CounterFilter.count";

    /**
     * Attribute index - The counter attribute.
     */
    protected static int ATTR_COUNTER = -1 ;

    static {
        Attribute a   = null ;
        Class     clsnull ;
        
        try {
            cls = Class.forName("org.w3c.jigsaw.filters.CounterFilter") ;
        } catch (Exception ex) {
            ex.printStackTrace() ;
            System.exit(1) ;
        }
        // Declare the counter attribute
        a = new IntegerAttribute("counter"
                                 , new Integer(0)
                                 , Attribute.EDITABLE) ;
        ATTR_COUNTER = AttributeRegistry.registerAttribute(cls, a) ;
    }

    /**
     * We count all accesses, even the one that failed.
     * We also define the 
     * <code>org.w3c.jigsaw.filters.CounterFilter.count</code>
     * request state as the number of hits on that resource (stored as
     * an Integer instance).
     * @param request The request being processed.
     * @return Always <strong>null</strong>.
     */

    public synchronized ReplyInterface ingoingFilter(RequestInterface req) {
        Request request = (Request) req;
        int i = getInt (ATTR_COUNTER, 0) + 1;
        setInt(ATTR_COUNTER, i) ;
        if(! request.hasState(STATE_COUNT))
            request.setState(STATE_COUNT, new Integer(i)) ;
        return null;
    }

}
That's all ! However, this needs a bit more explanations. First of all, you might be surprised that we didn't provide an implementation for the outgoingFilter method. There is one reasons for this: our super-class provide an empty outgoingFilter method, this solves the compiler problem.

Note that the counter value will be made persistent across servers invocation by the Jigsaw runtime. To be clear, this means that you can shutdown the server, and restart it: the count will keep up to date. Now, enough coding, let's play with our filter, the next section explains how to attach an instance of the filter to some target resource.

Installing the filter

First, let's decide on some resource we want to count access to. For the sake of simplicity, let's say we want to count the number of accesses to the /User directory resource. As you might have guess, the first thing we want to do is to launch the admin tool. Then setting up a filter to the /User directory resource involves the followings steps:
  1. Select the "User" node in the tree.
  2. Click on the "Frames" button.
  3. Expand the "User" node in the little tree (you should see a HTTPFrame or any subclass).
  4. Select the HTTPFrame node.
  5. Click on "Back to Add Frame menu"
  6. Then select the filter's class (ie org.w3c.jigsaw.filters.CounterFilter)
  7. Click on "Add Frame"
Now your filter is added, but we could need to customize it:
  1. Click on the "Frames" button of the "User" node. (previous steps 1,2,3)
  2. Expand the little tree (right part of the window)
  3. Select the "CounterFilter" node
  4. Change the attribute you want. In this case, you don't need to change anything. (Don't forget to commit your changes)
The actual count is 0, and we don't care about the filter's name.

Now, we can access /User (point your browser to /User). Reload the filter's editor...the value is now 1.
 

Further reading

If you want to understand better the concept of filters, then you can look at the available filters, here is a path (by increasing complexity): Enjoy !