// FilteredResource.java
// $Id: FilteredResource.java,v 1.17 1997/03/28 16:14:51 abaird Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.resources ;

import java.util.* ;
import java.io.* ;

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

/**
 * Filtered resources.
 * A filtered resource is a resource that can be filtered through any filters.
 * Filters are trigered at three points during request processing:
 * <ul>
 * <li>During the lookup, so that they have a chance to check any access
 * rights,
 * <li>Before the request is actually processed by its target resource,
 * <li>And optionally, after the request has been processed (depending on
 * the return value of the second stage.).
 * </ul>
 * @see w3c.jigsaw.resources.ResourceFilter
 */

public class FilteredResource extends HTTPResource {
    /**
     * The special class of ResourceFrame we know of.
     */
    protected static Class filterClass = null;
    
    static {
	try {
	    filterClass = Class.forName("w3c.jigsaw.resources.ResourceFilter");
	} catch (Exception ex) {
	    throw new RuntimeException("No ResourceFilter class found.");
	}
    }

    /**
     * Get our whole list of filters.
     */

    public synchronized ResourceFilter[] getFilters() {
	ResourceFrame frames[] = collectFrames(filterClass);
	if ( frames != null ) {
	    // FIXME Normally a simple cast should suffice (?)
	    ResourceFilter f[] = new ResourceFilter[frames.length];
	    for (int i = 0 ; i < frames.length ; i++)
		f[i] = (ResourceFilter) frames[i];
	    return f;
	}
	return null;
    }
    
    /**
     * Get the list of filters of this class.
     * @param cls The class of filters requested.
     * @return An array of filters, which are instances of the given class.
     */
    
    public synchronized ResourceFilter[] getFilters(Class cls) {
	ResourceFrame frames[] = collectFrames(cls);
	if ( frames != null ) {
	    // FIXME Normally a simple cast should suffice (?)
	    ResourceFilter f[] = new ResourceFilter[frames.length];
	    for (int i = 0 ; i < frames.length ; i++)
		f[i] = (ResourceFilter) frames[i];
	    return f;
	}
	return null;
    }

    /**
     * Register a new filter to this resource.
     * This method register a new filter to the this filtered resource. The
     * provided filter should be an <em>uninitialized</em> ResourceFilter
     * instance.
     * @param The uninitialized filter.
     */

    public synchronized void registerFilter(ResourceFilter filter
					    , Hashtable defs) {
	if ( defs == null ) 
	    defs = new Hashtable(3);
	defs.put("target", this);
	registerFrame(filter, defs);
    }

    /**
     * Unregister a filter to this target.
     * @param filter The filter to unregister.
     */

    public synchronized void unregisterFilter(ResourceFilter filter) {
	unregisterFrame(filter);
    }

    /**
     * Register our filters, if any in the lookup result object.
     * Sub-classes of the FilteredResource class should either register 
     * their filters themselves, or call their super method. The latest
     * way is prefered, of course.
     * @param ls The current lookup state.
     * @param lr The lookup result, being constructed.
     * @exception HTTPException If something went wrong.
     * @return A boolean, <strong>true</strong> if lookup has found
     * a terminal node, <strong>false</strong> otherwise. In the latter case,
     * the caller should make sure to continue the lookup process.
     */

    public boolean lookup(LookupState ls, LookupResult lr) 
	throws HTTPException
    {
	HTTPFilter filters[] = getFilters();
	if ( filters != null ) {
	    // Mark filters, for them to be called at outgoing time:
	    lr.addFilters(filters);
	    // Some clever filter around ?
	    for (int i = 0 ; i < filters.length ; i++) {
		if ( filters[i] == null )
		    continue;
		if ( filters[i].lookup(ls, lr) )
		    return true;
	    }
	}
	return super.lookup(ls, lr);
    }

    /**
     * Initialize the filters of that filtered resource.
     * @param values Default attribute values.
     */

    public void initialize(Object values[]) {
	super.initialize(values);
	// Initialize the filters if any.
	ResourceFilter filters[] = getFilters();
	if ( filters != null ) {
	    Hashtable defs = new Hashtable(3);
	    defs.put("target", this);
	    for (int i = 0 ; i < filters.length ; i++) {
		if ( filters[i] == null )
		    continue;
		filters[i].initialize(defs);
	    }
	}
    }
}



