HI all:
  I have implemented and External Cache Invalidator object and server to 
implement a synchorized way for invalidating Cocoon2's cached pages 
(from outside) through an simple XSP page that interpret an HTTP post 
message.
  This solution is implemented by DB Prism Generator for Cocoon2 and is 
usefull for making (using content agregation) news feeds "a la" My 
yahoo, this kind of news feed are implemented selecting the news from a 
simple table inside the database, this news are only invalidated when 
the database process an update/insert or delete on the corrected table 
that fires a trigger which send an http messages to the invalidator XSP 
page, this message includes information about the url arguments and 
cookies used to indentified the page. When this message is processed by 
the invalidator XSP page contact the invalidator server and enqueue the 
message.
  Cocoon will ask to the ExternalCacheValidity which implements the 
interface CacheValidity for the validity of the page, this object 
contact the invalidator server and return true or false depending on the 
response of the External invalidator server.
  Here the class which implement the previous functionality:
     - com.prism.components.cache.Server (Interface which is an Avalon 
component and defines the functionality of External Invalidator Servers)
     - com.prism.components.cache.InMemoryServerImpl (Concrete Class 
which implements the previous one interface and provide an InMemory 
implementation of the Invalidator container, this class uses a HashMap 
for storing cached pages keys and a linked list for implementing the 
queue of invalidation messages)
    - com.prism.caching.ExternalCacheValidity ( implements 
org.apache.cocoon.caching.CacheValidity and return true or false if the 
pages is cached by the external invalidator server.
Note: Cached by the external invalidator server means that this page is 
not stored by the server, the pages is stored in the Cocoon cache 
system, this server only register an encoded url which identified the 
page and return true or false if the page is valid.
  - An XSP page invalidte.xsp, which receives http post messages whith 
the pages to be removed from the server.
 Usabilty, DBPrismGenerator uses this technique interpreting an internal 
sitemap argument named Cache-Control, here an example of this setting:
   <map:match pattern="header/**.xml">
    <map:generate type="db" src="/cms/CMSj.header">
        <map:parameter name="Cache-Control" value="External"/>
        <map:parameter name="source" value="/{1}.xml"/>
        <map:parameter name="printable" value="no"/>
    </map:generate>
    <map:serialize/>
   </map:match>
  This means that the resource will be resolved by DBPrismGenerator 
(type=db) and this generator returns on the method generateValidity() an 
object of type ExternalCacheValidity, here the code:
      ....
      } else if (this.cacheControl==Server.EXTERNAL) {
        if (getLogger().isDebugEnabled())
             getLogger().debug("generateValidity called returning 
ExternalCacheValidity");
        return new 
ExternalCacheValidity(this.generateKey(),this.cacheServer,this.encodedURL);
      ....
   This external cache validity objects is identified by a unique key 
(generated by the CacheServer) and the encoded url, the encoded url is 
generated with the syntax 
/path/object?arg1=val1&arg2=val&Coookie:name1=val1&Cookie:name2=val2, 
this url is used then to ask for the availibilty of the page on the 
server or not.
   DBPrismGenerator uses this object but, its possible to use into an 
XSP page too.
   Here an example of the invalidation message sent by the database to 
Cocoon to invalidate an specific page:
POST /dbprism/x-dbprism-cache-invalidate HTTP/1.0
Authorization: BASIC YWRtaW5pc3RyYXRvcjoxMjM=
Content-Length: 439

<?xml version="1.0"?>
<invalidation>
  <url exp="/cms/CMSj.content" prefix="no">
    <validity level="0"/>
    <sitemap-argument name="source" value="/Home.xml"/>
    <sitemap-argument name="printable" value="no"/>
  </url>
  <url exp="/cms/CMSj.header" prefix="no">
    <validity level="0"/>
    <sitemap-argument name="source" value="/Home.xml"/>
    <sitemap-argument name="printable" value="no"/>
  </url>
</invalidation>

   Obviusly the External Cache Invalidator server use an username and 
password to validate the request which arrive from outside Cocoon, this 
user/password is encoded into http header Authorization in Base 64 form 
(in this case Administrator/123), this invalidation xml message means 
that the XSP will invalidate two pages (/cms/CMSj.content and 
/cms/CMSj.header) with the corresponding arguments, the option 
prefix=yes|no is reserved for future use for implementing massive 
invalidation message using regexp. Also validity=0..9 is reserved for 
future use on the Cache Server if it imlement and prioritized list of 
invalidation messages, this mean that messages with different validities 
will re-order in the invalidation queue.
   Here an example of an Oracle trigger which sends an invalidation 
message to Cocoon when a user update a CMS page :
CREATE OR REPLACE TRIGGER CMS_INVALID_TRIG
  AFTER UPDATE on pages
  for each row
   BEGIN
     cms_invalidate_proc('cocoonhost',8888,:new.path||:new.name||'.xml');
   END;
  It uses an stored procedure cms_invalidate_proc which compose the xml 
post message showed above.
  I attached the sources of the class and examples for more information.
  Best regards, Marcelo.

PD: Sorry for a long email, but I thing that this implementation could 
be usefull for other users.
/***************************************************************************** * Copyright (C) Marcelo F. Ochoa. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package com.prism.caching; import org.apache.cocoon.caching.CacheValidity; import com.prism.components.cache.Server; /** * A validation object for External invalidation functionality. * This is might be the most used CacheValidity object for DB Prism. * * @author Marcelo F. Ochoa */ public final class ExternalCacheValidity implements CacheValidity { private long key; private Server cacheServer; private String url; public ExternalCacheValidity(long keyToBeCached, Server globalCacheServer, String encodedURL) { this.key = keyToBeCached; this.cacheServer = globalCacheServer; this.url = encodedURL; } public boolean isValid(CacheValidity validity) { if (validity instanceof ExternalCacheValidity) { return this.cacheServer.isRegistered(url); } return false; } public long getKey() { return this.key; } public String toString() { return "ExternalCacheValidity: " + this.key; } }
/*****************************************************************************
 * Copyright (C) Marcelo F. Ochoa. All rights reserved.                      *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/
package com.prism.components.cache;

import org.apache.avalon.framework.activity.Startable;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.components.store.Store;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.util.HashUtil;

import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
import java.util.Random;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Cookie;

/**
 * This class runs as Thread to invalidate pages from DB Prism.
 *
 * @author <a href="mailto:[EMAIL PROTECTED]";>Marcelo F. Ochoa</a>
 */
public class InMemoryServerImpl extends AbstractLoggable implements Server, 
Configurable,
                                                                  ThreadSafe,
                                                                  Composable,
                                                                  Runnable,
                                                                  Startable {
  /** Provide a random key to avoid file caching by MRUStore */
  private Random rnd = null;

  /** HashMap to store cached pages */
  private HashMap cachedPages = null;

  /** How many second wait to get messages from invalidation queue*/
  private int cleanupthreadinterval;

  /** Queue used for invalidation purpose, 
    * an XSP page will populate this list with the key of pages to be invalidated
    * "run" method of the Thread class consume this list
    * In a future could be replaced by an JMS queue sorted by priority
    */
  private LinkedList invalidationQueue = null;

  /** Check if the server has already been started */
  private boolean started = false;

  /** boolean flag to stop the server */
  private boolean stop = false;

  private String invalidatorUser;
  private String invalidatorPassword;

  private ComponentManager manager;


/**
  * Get components of the ComponentManager
  *
  * @param the ComponentManager
  */
  public void compose(ComponentManager manager) throws ComponentException {
    this.manager = manager;
  }

/**
  * Initialize the InMemoryServerImpl.
  * it requires severel parameters into cocoon.xconf, also requires an entry in 
cocoon.roles
  * cocoon.roles:
  <role name="com.prism.components.cache.Server"
       shorthand="cache-server"
       default-class="com.prism.components.cache.InMemoryServerImpl"/>
  * cocoon.xconf:
  <cache-server class="com.prism.components.cache.InMemoryServerImpl" 
                 pool-max="1" pool-min="1">
     <parameter name="initialCapacity" value="500"/>
     <parameter name="loadFactor" value="50"/>
     <parameter name="invalidator-user" value="administrator"/>
     <parameter name="invalidator-pass" value="123"/>
     <parameter name="Cleanup-Thread-Interval" value="1"/>
  </cache-server>
  * where: 
  * - initialCapacity and loadFactor: controls the initialization of the HashMap used 
for storing pages keys
  * - invalidator-user and invalidator-pass: username and password used for 
autorization purposes
  * - Cleanup-Thread-Interval: greace periods in seconds betwen every chech into 
invalidation queue
  */
  public void configure(Configuration conf) throws ConfigurationException {
    Parameters params = Parameters.fromConfiguration(conf);
    invalidationQueue = new LinkedList();
    int initialCapacity = params.getParameterAsInteger("initialCapacity",10);
    int loadFactor = params.getParameterAsInteger("loadFactor",5);
    cleanupthreadinterval = params.getParameterAsInteger("Cleanup-Thread-Interval",1);
    invalidatorUser = params.getParameter("invalidator-user","invalidator");
    invalidatorPassword = params.getParameter("invalidator-pass","invalidator");
    //System.out.println("Server configure initialCapacity="+initialCapacity+" 
loadFactor="+loadFactor);
    cachedPages = new HashMap(initialCapacity,loadFactor);
    rnd = new Random(System.currentTimeMillis());
    if (getLogger().isDebugEnabled())
      this.getLogger().debug("Configure InMemoryServerImpl with loadFactor="+
          loadFactor+" initialCapacity="+initialCapacity+" Cleanup-Thread-Interval="+
          cleanupthreadinterval);
  }

/** 
  * Start the server
  */
  public void start() {
      //System.out.println("Server start");
      Thread server = new Thread(this);
      if (getLogger().isDebugEnabled())
        this.getLogger().debug("Starting DB Prism External Cache Server Invalidator 
thread");
      server.setPriority(Thread.MIN_PRIORITY); // nice process, runs with low priority
      server.setDaemon(true);
      server.setName("DB Prism Cache Server");
      server.start();
  }

/** 
  * Stop the server by signalling the stop flags
  */
  public void stop() {
    //System.out.println("Server stop");
    if (getLogger().isDebugEnabled())
      this.getLogger().debug("Stoping DB Prism External Cache Server thread");
    this.stop = true;
  }

/** 
  * Run the server
  * Gets an element from invalidation queue every Cleanup-Thread-Interval seconds
  * and remove it from cachedPages HashMap.
  */
  public void run() {
      if(!started) {
          //System.out.println("Server run");
          started = true;
          if (getLogger().isDebugEnabled())
            getLogger().debug("DB Prism External Cache Server running");
          while(!this.stop) {
              // to be implement;
              synchronized(invalidationQueue) {
                if (!this.invalidationQueue.isEmpty()) {
                  // consume once page
                  String key = (String)this.invalidationQueue.getFirst();
                  if (getLogger().isDebugEnabled())
                    getLogger().debug("DB Prism External Cache Server remove "+key);
                  synchronized(cachedPages) {
                    cachedPages.remove(key);
                  }
                  invalidationQueue.removeFirst();
                  //System.out.println("Remove key="+key);             
                }
              }
            try {
                Thread.currentThread().sleep(this.cleanupthreadinterval * 1000);
            } catch (InterruptedException ignore) {}
          }
      }
  }

  public long generateKey(String encodedURL) 
    throws ParameterException { 
      if (this.cachedPages.containsKey(encodedURL))
        return java.lang.Long.parseLong((String)this.cachedPages.get(encodedURL));
      else {
        StringBuffer keyString = new 
StringBuffer(String.valueOf(Math.abs(rnd.nextInt())));
        keyString.append(":").append(encodedURL);
        return HashUtil.hash(keyString.toString());
      }
    }

/**
  * Generates an unique key for a given page.
  * This key is generated using the url, the parameter list and the cookies
  * cancatenated as a string like this:
  * /cms/get.Content?source=/Home.xml&printable=no&Cookie:lang=es
  * then uses HashUtil.hash method to generate an unique long value
  */
  public String encodeURL(String url,
                          Parameters sitemapParameters,
                          HttpServletRequest httpRequest)
      throws ParameterException {
      boolean includeHttpParameters = false;
      Cookie [] cookies = null;
      StringBuffer keyString = new StringBuffer(url);
      String names[] = sitemapParameters.getNames();
      if (names.length>0)
        keyString.append("?");
      for(int i=0;i<names.length;i++)
        if (names[i].equalsIgnoreCase(this.COPY_ARG_NAME)) 
          includeHttpParameters = true;
        else if (names[i].equalsIgnoreCase(this.CACHE_CONTROL_ARG_NAME))
          continue;
        else
          
keyString.append(names[i]).append("=").append(sitemapParameters.getParameter(names[i])).append("&");
      if (includeHttpParameters && httpRequest!=null) {
        Enumeration  ite = httpRequest.getParameterNames();
        while(ite.hasMoreElements()) {
          String name = (String)ite.nextElement();
          String value = (String)httpRequest.getParameter(name);
          keyString.append(name).append("=").append(value).append("&");
        }
      }
      if (includeHttpParameters && httpRequest!=null && (cookies = 
httpRequest.getCookies())!=null)
        for(int i=0;i<cookies.length;i++)
          
keyString.append("Cookie:").append(cookies[i].getName()).append("=").append(cookies[i].getValue()).append("&");
      //System.out.println("generate key called with "+keyString.toString());
      String key = keyString.toString();
      int l = key.length();
      if (getLogger().isDebugEnabled())
        getLogger().debug("DB Prism Cache Server generating key: "+key);
      if (key.charAt(l-1)=='?' || key.charAt(l-1)=='&')
        return key.substring(0,l-1);
      else
        return key;
  }

/**
  * Checks is the given key is cached
  */
  public boolean isRegistered(String encodedURL) {
    //System.out.println("isRegisterd key: "+key);
    if (getLogger().isDebugEnabled())
        getLogger().debug("DB Prism Cache Server is register key: "+encodedURL);
    return cachedPages.containsKey(encodedURL);
  }

/**
  * Register the key as external cacheable page
  */
  public void registerCacheablePage(String encodedURL, long key) 
    throws ParameterException {
    //System.out.println("registerCacheablePage key: "+key);
    if (getLogger().isDebugEnabled())
        getLogger().debug("DB Prism Cache Server register cacheable page with key: 
"+encodedURL);
    this.cachedPages.put(encodedURL,java.lang.Long.toString(key));
  }

/**
  * Removes the key as external cacheable page
  * requires a valid username and password
  * validity value is reserved for future uses to implement a prioritized queue
  */
  public void removeCacheablePage(String username,
                                  String password,
                                  String encodedURL, 
                                  int validity)
    throws ProcessingException {
    //System.out.println("removeCacheablePage key: "+encodedURL);
    if (getLogger().isDebugEnabled())
        getLogger().debug("DB Prism Cache Server queue remove cacheable page with key: 
"+encodedURL+" validity="+validity);
    if (!this.invalidatorUser.equals(username) ||
        !this.invalidatorPassword.equals(password))
        throw new ProcessingException("External Cache Invalidation Server: bad 
username/password");
    if (this.cachedPages.containsKey(encodedURL))
      this.invalidationQueue.addLast(encodedURL);
    else
      throw new ProcessingException("External Cache Invalidation Server: this page not 
found");
  }
}
/***************************************************************************** * Copyright (C) Marcelo F. Ochoa. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package com.prism.components.cache; import javax.servlet.http.HttpServletRequest; import org.apache.avalon.framework.component.Component; import org.apache.cocoon.ProcessingException; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.parameters.ParameterException; /** * * @author Marcelo F. Ochoa */ public interface Server extends Component { String ROLE = "com.prism.components.cache.Server"; public static final int NONE = 0; public static final int EXTERNAL = 1; public static final int NOP = 2; public static final String COPY_ARG_NAME = "Copy-Request-Arguments"; public static final String CACHE_CONTROL_ARG_NAME = "Cache-Control"; public static final String CACHE_CONTROL_EXTERNAL = "External"; public static final String CACHE_CONTROL_NOP = "NOP"; public static final String CACHE_CONTROL_NONE = "no-cache"; /** * Checks is the given key is cached */ public boolean isRegistered(String encodedURL); /** * Register the key as external cacheable page */ public void registerCacheablePage(String encodedURL, long key) throws ParameterException; /** * Removes the key as external cacheable page * requires a valid username and password * validity value is reserved for future uses to implement a prioritized queue */ public void removeCacheablePage(String username, String password, String encodedURL, int validity) throws ProcessingException; /** * Generates an unique key for a given encoded url page. * This key is generated using generateKey and random value */ public long generateKey(String encodedURL) throws ParameterException; /** * Generates an unique key for a given page. * This key is generated using the url, the parameter list and the cookies * cancatenated as a string like this: * /cms/get.Content?source=/Home.xml&printable=no&Cookie:lang=es * then uses HashUtil.hash method to generate an unique long value */ public String encodeURL(String url, Parameters sitemapParameters, HttpServletRequest httpRequest) throws ParameterException; }
/*****************************************************************************
 * Copyright (C) Marcelo F. Ochoa. All rights reserved.                      *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/

package com.prism;
import com.prism.components.cache.Server;
import com.prism.caching.ExternalCacheValidity;
import com.prism.utils.Block;
import com.prism.utils.CocoonRequestWrapper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.StringReader;
import java.io.Reader;
import java.security.Principal;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;
import java.util.StringTokenizer;
import java.util.Calendar;
import java.util.TimeZone;
import org.apache.avalon.excalibur.pool.Recyclable;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.caching.CacheValidity;
import org.apache.cocoon.caching.Cacheable;
import org.apache.cocoon.caching.NOPCacheValidity;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.parser.Parser;
import org.apache.cocoon.environment.Context;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Response;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.http.HttpEnvironment;
import org.apache.cocoon.generation.ComposerGenerator;
import org.apache.cocoon.xml.AbstractXMLProducer;
import org.apache.cocoon.xml.XMLProducer;
import org.apache.cocoon.util.HashUtil;
import org.apache.log.Logger;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;

/**
  * Parallel content agregation
  * Problem: DBPrismGenrator divides the XML generation in two stages
  * at setup time DBPrismGenerator create a private Thread (delayer) which
  * calls to DBPrism.makePage method, then permits to Cocoon2's threads to continue
  * with other process.
  * At setup time DBPrismGenerator uses Block class  (blocker) as private semaphore 
which
  * locks generate method until the makePage operation is finished.
  * When makePage finish (run method of Delayer) unlock the semaphore permiting
  * to DBPrismGenerator to continue with the generation step calling to 
DBPrism.getPage()
  * flow:
  *  - Cocoon2 setup stage (in parallel)
         --> setup (part1) (Start a private engine 1 in parallel)
         --> setup (part2) (Start a private engine 2 in parallel)
         --> setup (partn) (Start a private engine 1 in parallel)
     - Cocoon2 generate stage (Sequencially gets the content of the parts)
         --> generate (part1) (Wait until engine 1 finish)
         --> generate (part2) (Wait until engine 2 finish)
         --> generate (partn) (Wait until engine n finish)
     - Serialize stage.
  */

/**
  * Allows DB Prism to be used as a Cocoon2's generator.
  *
  * @author <a href="mailto:[EMAIL PROTECTED]";>Marcelo F. Ochoa</a>
  */
public class DBPrismGenerator extends ComposerGenerator 
   implements Composable, Configurable, Recyclable, Cacheable, Contextualizable{

   protected Request request=null;
   protected Response response=null;
   protected Context context=null;
   protected HttpServletRequest httpRequest = null;
   protected DBPrism engine = null;
   protected CocoonRequestWrapper req = null;
   protected Delayer delayer = null;
   protected Block blocker = null;
   protected Server cacheServer = null;
   protected long key = 0;
   protected String encodedURL;
   protected int cacheControl = 0;

/** Contextualize this class
  * Stores context information to be use by configure method in order to resolve
  * /prism.properties as $WEBAPP/prism.properties in servlet 2.2+ containers
  */
  public void contextualize(org.apache.avalon.framework.context.Context ctx) throws 
ContextException {
    //System.out.println("contextualize called id="+this.toString());
    this.context = (Context)ctx.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
  }
  
/**
  * Set the sitemap-provided configuration. 
  * @param conf The configuration information
  * @exception ConfigurationException
  * For example (on Cocoon sitemap.xmap):
  * <map:generators default="file">
  *   ....
  *  <map:generator  name="db" src="com.prism.DBPrismGenerator" 
properties="./applications/dbprism/dbprism/prism.properties"/>
  *  ....
  * </map:generators>   
  **/
  public void configure(Configuration conf) throws ConfigurationException {
      String propfilename = conf.getAttribute("properties",DBPrism.PROPERTIES);
      try {
        if (propfilename.equals(DBPrism.PROPERTIES)) // converts to CONTEXT form
          propfilename = 
this.context.getResource("/").toExternalForm()+DBPrism.PROPERTIES.substring(1);
        //System.out.println("configure called properties="+propfilename);
        DBPrism.initDBPrism(propfilename);
      } catch (Exception e) {
        throw new ConfigurationException("Can't init DB Prism Engine: "+e.toString());
      }
  }
    
/**
  * Generate the unique key.
  * This key must be unique inside the space of this component.
  *
  * @return The generated key hashes the src
  */
  public long generateKey() {
    try {
      if (this.key!=0)
        return key; // reduce overhead to generateKey method
      else
        this.key = cacheServer.generateKey(this.encodedURL);
        return this.key;
    } catch (Exception pe) {
      if (getLogger().isDebugEnabled())
        getLogger().debug("generateKey Exception, returning 0",pe);
      return 0;
    }
  }

/**
  * Generate the validity object.
  *
  * @return The generated validity object or <code>null</code> if the
  *         component is currently not cacheable.
  */
  public CacheValidity generateValidity() {
      //System.out.println("generateValidity called");
      if (this.cacheControl==Server.NOP) {
        if (getLogger().isDebugEnabled())
           getLogger().debug("generateValidity called returning NOPCacheValidity");
        return new NOPCacheValidity();
      } else if (this.cacheControl==Server.EXTERNAL) {
        if (getLogger().isDebugEnabled())
           getLogger().debug("generateValidity called returning 
ExternalCacheValidity");
        return new 
ExternalCacheValidity(this.generateKey(),this.cacheServer,this.encodedURL);
      } else {// default null
        if (getLogger().isDebugEnabled())
           getLogger().debug("generateValidity called returning null");
        return null;
      }
  }

/**
  * Recycle the generator by removing references
  */
   public void recycle() {
       if (blocker!=null) {
         blocker.lock(engine); // Block this engine, wait until Delayer finish
         try {
           // free dbprism connection
           engine.recycle(this.req);
         } catch (SQLException sqe) { }; // Ignore
       }
       super.recycle();
       this.request = null;
       this.response = null;
       this.context = null;
       this.httpRequest = null;
       this.engine = null;
       this.req = null;
       this.delayer = null;
       this.blocker = null;
       this.cacheServer = null;
       this.key = 0;
       this.encodedURL = null;
      if (getLogger().isDebugEnabled())
        getLogger().debug("Recycle called");
       //System.out.println("Recycle called id="+this.toString());
   }

   public void setup(SourceResolver resolver, Map objectModel, String src, Parameters 
par)
       throws ProcessingException, SAXException, IOException {
     String cacheControlStr;
     //System.out.println("setup called id="+this.toString());
     super.setup(resolver, objectModel, src, par);
     if (getLogger().isDebugEnabled())
       getLogger().debug("setup called url: " + src + " instance="+this.toString());
     try {
        this.cacheServer = (Server) this.manager.lookup(Server.ROLE);
     } catch (ComponentException ce) {
        throw new ProcessingException("Can't get External invalidator server 
instance");
     }
     this.request = (Request) objectModel.get(Constants.REQUEST_OBJECT);
     this.context = (Context) objectModel.get(Constants.CONTEXT_OBJECT);
     this.response = (Response) objectModel.get(Constants.RESPONSE_OBJECT);
     cacheControlStr = 
par.getParameter(Server.CACHE_CONTROL_ARG_NAME,Server.CACHE_CONTROL_NONE);
     if (cacheControlStr.startsWith(Server.CACHE_CONTROL_EXTERNAL)) {
        cacheControl = Server.EXTERNAL;
     } else if (cacheControlStr.equalsIgnoreCase(Server.CACHE_CONTROL_NOP))
        cacheControl = Server.NOP;
     else
        cacheControl = Server.NONE;
     // ensure that we are running in a servlet environment
     this.httpRequest =
            (HttpServletRequest)objectModel.get(HttpEnvironment.HTTP_REQUEST_OBJECT);
     if (this.httpRequest == null) {
          throw new ProcessingException("HttpServletRequest object not available");
     }
     String url = this.resolver.resolve(this.source).getSystemId();
     // Guarantee src parameter is a file
     if (!url.startsWith("file:/"))
        throw new IOException("Protocol not supported: " + url);
     url = url.substring(5);
     req = new CocoonRequestWrapper(httpRequest,url,par);
     try {
       this.encodedURL = 
          cacheServer.encodeURL(
            this.source,this.parameters,this.httpRequest);
     } catch (ParameterException pe) {
        throw new ProcessingException("Can't encode the url",pe);
     }
     if (this.cacheControl==Server.EXTERNAL &&
         cacheServer.isRegistered(this.encodedURL)) {
       // do not start page generation
       if (getLogger().isDebugEnabled())
         getLogger().debug("found a cached page for key: " + this.generateKey());
       //System.out.println("setup found a cached page");
       return;
     }
     if (getLogger().isDebugEnabled())
       getLogger().debug("executing request:" + url + " instance="+this.toString());
     engine = new DBPrism();
     blocker = new Block();
     blocker.lock(engine); // Block this engine until the delayer is started
     delayer = new Delayer(engine,req,blocker);
     delayer.start(); // Sent engine.makePage() message in background
     //System.out.println("setup starts a page generation with 
engine="+engine.toString());
  }

/**
  * Generate XML data from DB Prism Engine.
  * Wait until delayer finish his engine.MakePage call
  * and call to engine.getPage if everything is OK.
  */
  public void generate() 
        throws ProcessingException, IOException {
        long startTime = System.currentTimeMillis();
        //System.out.println("generate called id="+this.toString());
        //System.out.println("generate called with engine="+engine.toString());
        Parser parser = null;
        HttpServletResponse httpResponse =
            
(HttpServletResponse)this.objectModel.get(HttpEnvironment.HTTP_RESPONSE_OBJECT);
        if (httpResponse == null) {
          throw new ProcessingException("HttpServletResponse object not available");
        }
        try {
            // pipe the results into the parser
            parser = (Parser)this.manager.lookup(Parser.ROLE);
            parser.setConsumer(this.xmlConsumer);
            blocker.lock(engine); // Block this engine, wait until Delayer finish
            if (delayer.status == Delayer.NOTAUTOHRIZED) {
                sendUnauthorized(httpResponse,delayer.msg);
                try {
                  parser = (Parser)this.manager.lookup(Parser.ROLE);
                  parser.setConsumer(this.xmlConsumer);
                  parser.parse(new InputSource(new 
StringReader(DBPrism.UnauthorizedText)));
                } catch (SAXException e) {
                  if (getLogger().isDebugEnabled()) {
                    getLogger().debug("SAXException in generate()", e);
                    getLogger().debug("Embedded SAXException generate()", 
e.getException());
                  }
                  throw new ProcessingException("SAXException 
DBPrismGenerator.generate()",e.getException());
                } catch (ComponentException e) {
                  if (getLogger().isDebugEnabled()) {
                    getLogger().debug("ComponentException in generate()", e);
                    getLogger().debug("Embedded ComponentException in generate()", e);
                  }
                  throw new ProcessingException("ComponentException in 
DBPrismGenerator.generate()",e);
                }
            } else if (delayer.status == Delayer.GENERALERROR) {
                  if (getLogger().isDebugEnabled())
                    getLogger().debug("GeneralError in generate(): " + delayer.msg);
                  throw new ProcessingException("GeneralError in 
DBPrismGenerator.generate(): " + delayer.msg);
            } else if (delayer.status == Delayer.STOPED) {
                  if (getLogger().isDebugEnabled())
                    getLogger().debug("GeneralError in generate(): Delayer not 
started");
                  throw new ProcessingException("General Error 
DBPrismGenerator.generate(): Delayer not started");
            } else if (delayer.status == Delayer.FINISHED) {
                // if everything is OK, get the page from BLOB buffer.
                showPage(httpResponse,parser,engine.getPage(req));
                if (this.cacheControl==Server.EXTERNAL) // if eveything is OK, caches 
this page
                  
this.cacheServer.registerCacheablePage(this.encodedURL,this.generateKey());
            }
        } catch (SAXException e) {
            if (getLogger().isDebugEnabled()) {
              getLogger().debug("SAXException generate()", e);
              getLogger().debug("Embedded SAXException generate()", e.getException());
            }
            throw new ProcessingException("SAXException 
DBPrismGenerator.generate()",e.getException());
        } catch (IOException e) {
            if (getLogger().isDebugEnabled())
              getLogger().debug("IOException in generate()", e);
            throw new ProcessingException("IOException DBPrismGenerator.generate()",e);
        } catch (Exception e) {
            if (getLogger().isDebugEnabled())
              getLogger().debug("Exception in generate()", e);
            throw new ProcessingException("Exception DBPrismGenerator.generate()",e);
        } finally {
            blocker.unlock(engine); // unlock the engine
            // Cleanup local resources
            if (parser != null) this.manager.release(parser);
            if (getLogger().isDebugEnabled())
              getLogger().debug("processing time 
"+(System.currentTimeMillis()-startTime)+"ms.");
        }
  }

  public void sendUnauthorized(HttpServletResponse res, String msg)
  throws IOException {
    res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    // put your realm here
    res.setHeader("WWW-authenticate","basic realm=\"" + msg + "\"");
  }

/**
  * Process cookie definicion from Jxtp.sendCookie or Jxtp.removeCookie
  * Syntax definition from http://www.netscape.com/newsref/std/cookie_spec.html
  * See Jxtp package
  * Don't work with cookie definition greater than 255 char's (muti-line cookies)
  */
  public Cookie Make_Cookie(String s)
  { Cookie choc_chip;
    long age;
    // Divide the string cookie format in fields by the ;
    StringTokenizer st = new StringTokenizer(s,";");
    // the name = value pairs is required
    String s1 = (String) st.nextElement();
    choc_chip = new 
Cookie(s1.substring(0,s1.indexOf("=")),s1.substring(s1.indexOf("=")+1));
    //System.out.println("Name =>" + choc_chip.getName());
    //System.out.println("Value =>" + choc_chip.getValue());
    while(st.hasMoreElements()) {
      s1 = (String) st.nextElement();
      // Proccess the expires field
      if (s1.startsWith(" expires=")) {
         s1 = s1.substring(s1.indexOf("=")+1);
         try {
            // Convert the Date especification to Age format of Servlets Cookie
            // Acording to non deprected api of JDK 1.1
            DateFormat df = new SimpleDateFormat("EEE MMM-dd-yy HH:mm:ss zzz", 
java.util.Locale.US);
            Date expire = df.parse(s1);
            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
            cal.setTime(expire);
            if (cal.get(1)==1990 && cal.get(2)==0 && cal.get(0)==1) {
              // Option remove cookie
              age = 0;
            } else {
              // Session cookie or expire in the future
              java.util.Date now = new java.util.Date();
              age = (expire.getTime()-now.getTime())/1000;
              age = (age < 0 ? -1 : age);
            }
            choc_chip.setMaxAge((int)age);
            //System.out.println("Age =>" + choc_chip.getMaxAge());
         } catch(Exception e) {
            if (getLogger().isDebugEnabled())
              getLogger().warn("Invalid Date format en cookie String");
         }
      } // end if expires=
      // Proccess the path field
      if (s1.startsWith(" path=")) {
         // Set Path
         choc_chip.setPath(s1.substring(s1.indexOf("=")+1));
         //System.out.println("Path =>" + choc_chip.getPath());
      } // end if path=
      // Proccess the domain field
      if (s1.startsWith(" domain=")) {
         // Set Domain
         choc_chip.setDomain(s1.substring(s1.indexOf("=")+1));
         //System.out.println("Domain =>" + choc_chip.getDomain());
      } // end if domain=
      // Proccess the secure flags
      if (s1.startsWith(" secure")) {
         // Set Secure
         choc_chip.setSecure(true);
         //System.out.println("Secure");
      } // end if secure
    } // end while st.hasMoreElements
    // Return the cookie to the caller
    return choc_chip;
  }

/**
  * Returns the generated page (Reader) to the browser
  * check for the header to set the response object*/
  public void showPage(HttpServletResponse res,
                       Parser parser,
                       Reader page) throws Exception
  {
    char [] buff_out = new char[8192];
    BufferedReader in = new BufferedReader(page,8192);
    StringBuffer xmlPage = new StringBuffer(8192);
    int i;
    String s;
    s=in.readLine();
    if (s.startsWith("Location: ")) {
      s = s.substring(10);
      res.sendRedirect(s);
      if (getLogger().isDebugEnabled())
        getLogger().debug("Location header: "+s);
      return;
    } else if (s.startsWith("Content-type: ") || s.startsWith("Status: "))
      // Verify if the position 1..n have the Syntax "xxx : yyy"
      // handle special case of Cookie definition or Content-type
      // generated by owa_cookie.send or owa_util.mime_header
      // Cache-Control: public, is interpreted as Document Cacheable.
      // others header definitions are pased as is
      do { // Process each line of header
         if (s.startsWith("Content-type: "))
           continue; // Ignore Content-type, Cocoon handles the output method
         else if (s.startsWith("WWW-authenticate: ")) {
                String reason = s.substring(18).trim();
                if (getLogger().isDebugEnabled())
                  getLogger().debug("NotAuthorizedException Header ("+reason+")");
                sendUnauthorized(res,reason);
                parser.parse(new InputSource(new 
StringReader(DBPrism.UnauthorizedText)));
                return;
              } else if (s.startsWith("Set-Cookie: ")) { // Makes cookies
                      // Parse the cookie line
                      Cookie choc_chip = Make_Cookie(s.substring(12));
                      res.addCookie(choc_chip);
                      if (getLogger().isDebugEnabled())
                        getLogger().debug("Set-Cookie header: "+s.substring(12));
                   } else
                    try { // if dosn't cookie is another header info
                      res.setHeader(s.substring(0,s.indexOf(':')),
                      s.substring(s.indexOf(':')+2));
                      if (getLogger().isDebugEnabled())
                        getLogger().debug("SetHeader : "+s);
                    } catch (Exception e) { };
      } while ((s=in.readLine())!=null && s.length()>0); // End while header lines
    // Output the rest of generated page in htp.htbuf
    // send it without pay attention to new lines
    while ((i=in.read(buff_out))>0)
       xmlPage.append(buff_out,0,i);
    parser.parse(new InputSource(new StringReader(xmlPage.toString())));
  }

/**
  * Parallel content agregation
  * Problem: DBPrismGenrator divides the XML generation in two stages
  * at setup time DBPrismGenerator create a private Thread (delayer) which
  * calls to DBPrism.makePage method, then permits to Cocoon2's threads to continue
  * with other process.
  * At setup time DBPrismGenerator uses Block class as private semaphore which
  * locks generate method until the makePage operation is finished.
  * When makePage finish (run method of Delayer) unlock the semaphore permiting
  * to DBPrismGenerator to continue with the generation step calling to 
DBPrism.getPage()
  * flow:
  *  - Cocoon2 setup stage (in parallel)
         --> setup (part1) (Start a private engine 1 in parallel)
         --> setup (part2) (Start a private engine 2 in parallel)
         --> setup (partn) (Start a private engine 1 in parallel)
       - Cocoon2 generate stage (Sequencially gets the content of the parts)
         --> generate (part1) (Wait until engine 1 finish)
         --> generate (part2) (Wait until engine 2 finish)
         --> generate (partn) (Wait until engine n finish)
       - Serialize stage.
  */
  class Delayer extends Thread {
     static final int STOPED = 0;
     static final int RUNNING = 1;
     static final int NOTAUTOHRIZED = 2;
     static final int GENERALERROR = 3;
     static final int FINISHED = 4;
     int status = STOPED;
     String msg = "OK";
     private DBPrism dbEngine = null;
     private CocoonRequestWrapper theRequest = null;
     private Block theBlock = null;
     
     public Delayer(DBPrism eng, CocoonRequestWrapper request, Block blocker) throws 
ProcessingException {
        if (eng==null || request==null) // sanity checks
            throw new ProcessingException("DBPrism engine or request is null in 
Delayer");
        dbEngine = eng;
        theRequest = request;
        theBlock = blocker;
        status = STOPED;
     }
     
     public void run() {
        //System.out.println("Starting request to engine = "+dbEngine.toString());
        status = RUNNING;
        try {
            dbEngine.makePage(req);
            status = FINISHED;
        } catch (NotAuthorizedException ne) {
            status = NOTAUTOHRIZED;
            msg = ne.getMessage();
        } catch (Exception e) {
            status = GENERALERROR;
            msg = e.toString();
        } finally {
            theBlock.unlock(dbEngine); // Unblock the engine
            //System.out.println("Ending request to engine = "+dbEngine.toString());
            //System.out.println("Return Status ="+status);
            //System.out.println("Return Message="+msg);
            dbEngine = null;
            theRequest = null;
            theBlock = null;
        }
      }
  } // End inher class Delayer
}
<?xml version="1.0" encoding="ISO-8859-1"?>

<xsp:page
          language="java"
          xmlns:xsp="http://apache.org/xsp";
>
  <xsp:structure>
   <xsp:include>org.apache.cocoon.components.language.markup.xsp.XSPUtil</xsp:include>
   <xsp:include>org.apache.avalon.framework.context.ContextException</xsp:include>
   <xsp:include>org.apache.avalon.framework.parameters.Parameters</xsp:include>
   <xsp:include>org.apache.avalon.framework.parameters.ParameterException</xsp:include>
   <xsp:include>org.apache.cocoon.xml.XMLConsumer</xsp:include>
   <xsp:include>com.prism.components.cache.Server</xsp:include>
   <xsp:include>java.io.BufferedReader</xsp:include>
   <xsp:include>java.io.InputStreamReader</xsp:include>
   <xsp:include>java.util.Enumeration</xsp:include>
   <xsp:include>java.util.Hashtable</xsp:include>
   <xsp:include>java.util.HashMap</xsp:include>
   <xsp:include>java.util.Locale</xsp:include>
   <xsp:include>java.util.Vector</xsp:include>
   <xsp:include>java.security.Principal</xsp:include>
   <xsp:include>javax.servlet.http.HttpServletRequest</xsp:include>
   <xsp:include>javax.servlet.http.Cookie</xsp:include>
   <xsp:include>javax.servlet.http.HttpSession</xsp:include>
   <xsp:include>javax.servlet.ServletInputStream</xsp:include>
   <xsp:include>javax.servlet.RequestDispatcher</xsp:include>
   <xsp:include>org.apache.cocoon.environment.http.HttpEnvironment</xsp:include>
   <xsp:include>org.w3c.dom.Document</xsp:include>
   <xsp:include>org.xml.sax.Attributes</xsp:include>
   <xsp:include>org.apache.cocoon.xml.AbstractXMLPipe</xsp:include>
   <xsp:include>sun.misc.BASE64Decoder</xsp:include>
  </xsp:structure>
<xsp:logic><![CDATA[
     // Class attributes 
     private static String EXTRACT_URI="http://www.plenix.com/dbprism/invalidation";;
     private static String EXTRACT_ELEMENT_INVALIDATION="invalidation";
     private static String EXTRACT_ELEMENT_URI="url";
     private static String EXTRACT_ELEMENT_VALIDITY="validity";
     private static String EXTRACT_ELEMENT_COOKIE="cookie";
     private static String EXTRACT_ELEMENT_HTTP="http-argument";
     private static String EXTRACT_ELEMENT_ARGUMENT="sitemap-argument";
     Server cacheServer = null;
     String name = "";
     String passwd = "";
]]></xsp:logic>
<xsp:logic><![CDATA[
     // Inher class, private request
     // Note that it only implement getter/setter class for parameters and cookies
     // other methots returns null, be carefull with this.
     public class MyHtppRequest implements HttpServletRequest
     {
        HttpServletRequest request;
        Hashtable parameters;
        Vector cookies;
        MyHtppRequest(HttpServletRequest request) {
          this.cookies = null;
          this.request = request;
          this.parameters = new Hashtable();
        }    
        public String getAuthType(){ return request.getAuthType(); }
        public Cookie[] getCookies() { 
          if (cookies.isEmpty())
            return null;
          else
            return (Cookie[])cookies.toArray();
        }
        public void setCookies(Cookie cookie) { 
            cookies.add(cookie);
        }
        public long getDateHeader(String s){ return request.getDateHeader(s); }
        public String getHeader(String s){ return request.getHeader(s); }
        public Enumeration getHeaders(String s){ return request.getHeaders(s); }
        public Enumeration getHeaderNames(){ return request.getHeaderNames(); }
        public int getIntHeader(String s){ return request.getIntHeader(s); }
        public String getMethod(){ return request.getMethod(); }
        public String getPathInfo(){ return request.getPathInfo(); }
        public String getPathTranslated(){ return request.getPathTranslated(); }
        public String getContextPath(){ return request.getContextPath(); }
        public String getQueryString(){ return request.getQueryString(); }
        public String getRemoteUser(){ return request.getRemoteUser(); }
        public boolean isUserInRole(String s){ return request.isUserInRole(s); }
        public Principal getUserPrincipal(){ return request.getUserPrincipal(); }
        public String getRequestedSessionId(){ return request.getRequestedSessionId(); 
}
        public String getRequestURI(){ return request.getRequestURI(); }
        public String getServletPath(){ return this.getServletPath(); }
        public HttpSession getSession(boolean flag){ return request.getSession(flag); }
        public HttpSession getSession(){ return request.getSession(); }
        public boolean isRequestedSessionIdValid(){ return 
request.isRequestedSessionIdValid(); }
        public boolean isRequestedSessionIdFromCookie(){ return 
request.isRequestedSessionIdFromCookie(); }
        public boolean isRequestedSessionIdFromURL(){ return 
request.isRequestedSessionIdFromURL(); }
        public boolean isRequestedSessionIdFromUrl(){ return 
request.isRequestedSessionIdFromUrl(); }
        public Object getAttribute(String s){ return request.getAttribute(s); }
        public Enumeration getAttributeNames(){ return request.getAttributeNames(); }
        public String getCharacterEncoding(){ return request.getCharacterEncoding(); }
        public int getContentLength(){ return request.getContentLength(); }
        public String getContentType(){ return request.getContentType(); }
        public ServletInputStream getInputStream() throws IOException{ return 
request.getInputStream(); }
        public String getParameter(String s)
          { 
                return (String)this.parameters.get(s); 
          }
        public Enumeration getParameterNames()
          { 
                return this.parameters.keys(); 
          }
        public String[] getParameterValues(String s) {
                String [] val = new String[1];
                val[0] = (String)parameters.get(s);
                return val;
          }
        public void setParameter(String name, String value)
          { 
                this.parameters.put(name,value); 
          }          
        public String getProtocol(){ return request.getProtocol(); }
        public String getScheme(){ return request.getScheme(); }
        public String getServerName(){ return request.getServerName(); }
        public int getServerPort(){ return request.getServerPort(); }
        public BufferedReader getReader()
            throws IOException{ return request.getReader(); }
        public String getRemoteAddr(){ return request.getRemoteAddr(); }
        public String getRemoteHost(){ return request.getRemoteHost(); }
        public void setAttribute(String s, Object obj){ request.setAttribute(s,obj); }
        public void removeAttribute(String s){ request.removeAttribute(s); }
        public Locale getLocale(){ return request.getLocale(); }
        public Enumeration getLocales(){ return request.getLocales(); }
        public boolean isSecure(){ return request.isSecure(); }
        public RequestDispatcher getRequestDispatcher(String s){ return 
request.getRequestDispatcher(s); }
        public String getRealPath(String s){ return request.getRealPath(s); }
        public java.lang.StringBuffer getRequestURL() { return null; }
        public java.util.Map getParameterMap() 
          { 
            return null; 
          }
        public void setCharacterEncoding(java.lang.String $1) { }
     } // end inher class     
]]></xsp:logic>
<xsp:logic><![CDATA[
     // Inher class
     public class InvalidateExtractor extends AbstractXMLPipe
     {
        HttpServletRequest request;
        private int state = 0;
        int count = 0;
        private String url;
        private boolean prefix;
        private int validity;
        Parameters par;
        Cookie cookie;
        MyHtppRequest httpParameter;
        AttributesImpl xspAttr;
        InvalidateExtractor(XMLConsumer consumer, HttpServletRequest request) {
          this.xspAttr = new AttributesImpl();
          this.setConsumer(consumer);
          this.url = "";
          this.prefix = false;
          this.validity = 0;
          this.par = new Parameters();
          this.request = request;
          this.httpParameter = new MyHtppRequest(this.request);
          this.cookie = null;
          this.xspAttr.clear();
        }

        /**
          * Receive notification of the beginning of an element.
          *
          * @param uri The Namespace URI, or the empty string if the element has no
          *            Namespace URI or if Namespace
          *            processing is not being performed.
          * @param loc The local name (without prefix), or the empty string if
          *            Namespace processing is not being performed.
          * @param raw The raw XML 1.0 name (with prefix), or the empty string if
          *            raw names are not available.
          * @param a The attributes attached to the element. If there are no
          *          attributes, it shall be an empty Attributes object.
          */
    public void startElement(String uri, String loc, String raw,
                             Attributes a) throws SAXException {
      //System.out.println(" Start uri="+uri+" loc="+loc+" raw="+raw+" state="+state);
      if (state == 0 && EXTRACT_ELEMENT_INVALIDATION.equals(loc))
        state = 1;
      else if (state == 1 && EXTRACT_ELEMENT_URI.equals(loc)) {
        url = a.getValue("exp");
        prefix = "yes".equalsIgnoreCase(a.getValue("prefix"));
        state = 2;
        //System.out.println("url="+url + " prefix="+prefix);
      } else if (state == 2 && EXTRACT_ELEMENT_ARGUMENT.equals(loc)) {
        String name = a.getValue("name");
        String value = a.getValue("value");
        par.setParameter(name,value);
        //System.out.println("sitemap argument name="+name+" value="+value);
      } else if (state == 2 && EXTRACT_ELEMENT_HTTP.equals(loc)) {
        String name = a.getValue("name");
        String value = a.getValue("value");
        httpParameter.setParameter(name,value);
        //System.out.println("http argument name="+name+" value="+value);
      } else if (state == 2 && EXTRACT_ELEMENT_VALIDITY.equals(loc)) {
        validity = Integer.parseInt(a.getValue("level"));
        //System.out.println("url="+url + " prefix="+prefix + " validity="+validity);
      } else if (state == 2 && EXTRACT_ELEMENT_COOKIE.equals(loc)) {
        String name = a.getValue("name");
        String value = a.getValue("value");
        cookie = new Cookie(name,value);
        httpParameter.setCookies(cookie);
        //System.out.println("cookie name="+name+" value="+value);
      }
    }


        /**
          * Receive notification of the end of an element.
          *
          * @param uri The Namespace URI, or the empty string if the element has no
          *            Namespace URI or if Namespace
          *            processing is not being performed.
          * @param loc The local name (without prefix), or the empty string if
          *            Namespace processing is not being performed.
          * @param raw The raw XML 1.0 name (with prefix), or the empty string if
          *            raw names are not available.
          */
          public void endElement(String uri, String loc, String raw)
          throws SAXException {
             //System.out.println("End uri="+uri+" loc="+loc+" raw="+raw+" 
state="+state);
             if (state==2 && EXTRACT_ELEMENT_URI.equals(loc)) {
                state=1;
                try {
                  String key = cacheServer.encodeURL(url,par,httpParameter);
                  count++;
                  //System.out.println("remove key ="+key);
                  cacheServer.removeCacheablePage(name,passwd,key,validity);
                  xspAttr.addAttribute("", "expr", "expr", "CDATA", url);
                  xspAttr.addAttribute("", "id", "id", "CDATA", ""+count);
                  xspAttr.addAttribute("", "status", "status", "CDATA", "ok");
                  xspAttr.addAttribute("", "numinv", "numinv", "CDATA", "0");
                } catch (Exception e) {
                  xspAttr.addAttribute("", "expr", "expr", "CDATA", url);
                  xspAttr.addAttribute("", "id", "id", "CDATA", ""+count);
                  xspAttr.addAttribute("", "status", "status", "CDATA", "not found");
                  xspAttr.addAttribute("", "numinv", "numinv", "CDATA", "0");
                  System.out.println("Error in remove ="+e.getMessage());
                } finally {
                  this.contentHandler.startElement("", "url", "url", xspAttr);
                  this.url = "";
                  this.prefix = false;
                  this.validity = 0;
                  this.par = new Parameters();
                  this.httpParameter = new MyHtppRequest(this.request);
                  this.cookie = null;
                  this.xspAttr.clear();
                  this.contentHandler.endElement("", "url", "url");
               }
             }
             else if (state==1 && EXTRACT_ELEMENT_INVALIDATION.equals(loc))
                state=0;
          }
     }
]]></xsp:logic>

<invalidationresult><xsp:logic><![CDATA[    
     try {
        this.cacheServer = (Server) this.manager.lookup(Server.ROLE);
     } catch (ComponentException ce) {
        System.out.println("invalidate.xsp: Can't get External Invalidator Server 
instance");
     }
     HttpServletRequest httpRequest =
            (HttpServletRequest)objectModel.get(HttpEnvironment.HTTP_REQUEST_OBJECT);
     if (httpRequest == null) {
          throw new ProcessingException("HttpServletRequest object not available");
     }
     Parser parser = null;
     BASE64Decoder B64 = new BASE64Decoder();
     int i;
     String str;
     try {
        str = httpRequest.getHeader("Authorization").substring(6);
        str = new String(B64.decodeBuffer(str),"iso-8859-1");
     } catch (Exception e) {
        str = ":";
     }
     i = str.indexOf(':');
     name = str.substring(0,i);
     passwd = str.substring(i+1);
     BufferedReader ir = new BufferedReader(new 
InputStreamReader(httpRequest.getInputStream()));
     String line;
     StringBuffer msg = new StringBuffer();
     while((line=ir.readLine())!=null)
      msg.append(line+"\n");
     //System.out.println("User=>"+name);
     //System.out.println("Password=>"+passwd);
     //System.out.println("POST Message=>");
     //System.out.println(msg.toString());
     InvalidateExtractor extractor = new 
InvalidateExtractor((XMLConsumer)this.contentHandler,httpRequest);
     try {
       parser = (Parser)this.manager.lookup(Parser.ROLE);
       if (parser==null)
         System.out.println("Parser is null");
       else {
         parser.setConsumer(extractor);
         parser.parse(new InputSource(new StringReader(msg.toString())));
       }
     } catch (ComponentException e) {
        if (getLogger().isDebugEnabled()) {
          getLogger().debug("ComponentException in invalidate.generate()", e);
          getLogger().debug("Embedded ComponentException in invalidate.generate()", e);
        }
        //System.out.println("ComponentException="+e.getMessage());
    } catch (SAXException e) {
        if (getLogger().isDebugEnabled()) {
          getLogger().debug("SAXException in invalidate.generate()", e);
          getLogger().debug("Embedded SAXException in invalidate.generate()", e);
        }
        //System.out.println("SAXException="+e.getMessage());
     } catch (IOException e) {
        if (getLogger().isDebugEnabled()) {
          getLogger().debug("IOException in invalidate.generate()", e);
          getLogger().debug("Embedded IOException in invalidate.generate()", e);
        }
        //System.out.println("IOException="+e.getMessage());
     } finally {
       // Cleanup local resources
       if (parser != null) this.manager.release(parser);
     }
]]></xsp:logic></invalidationresult>
</xsp:page>
POST /dbprism/x-dbprism-cache-invalidate HTTP/1.0
Authorization: BASIC YWRtaW5pc3RyYXRvcjoxMjM=
Content-Length: 439

<?xml version="1.0"?>
<invalidation>
  <url exp="/cms/CMSj.content" prefix="no">
    <validity level="0"/>
    <sitemap-argument name="source" value="/Home.xml"/>
    <sitemap-argument name="printable" value="no"/>
  </url>
  <url exp="/cms/CMSj.header" prefix="no">
    <validity level="0"/>
    <sitemap-argument name="source" value="/Home.xml"/>
    <sitemap-argument name="printable" value="no"/>
  </url>
</invalidation>
-- Purpose: Demo Invalidation  Procedure
-- This file is part of DB Prism External Cache invalidator samples directory
--    Name: cms_invalidate_proc
--
-- Usage:
--    SQL> set serveroutput on (When debugging to see dbms_output.put_line's)
--    SQL> exec cms_invalidate_proc('cocoonhost',8888,'/Home.xml');
--
-- Next:  1. Needs Base64 password routine and params passed.
--           By the default include administrator/123 as username/password
--        2. Needs yes/no param..for prefix=yes|no but changes content-length
-- 
create or replace procedure cms_invalidate_proc (
                                machine in varchar2, 
                                port in integer, 
                                uri in varchar2 ) is  
  d integer;
  c  utl_tcp.connection;  -- TCP/IP connection to the Web server
  DQUOTE constant varchar2(1) :=  chr(34);
  CR constant varchar2(1) :=  chr(13);
  content_length integer;
  invalidate_msg varchar2(4000);

BEGIN
-- Note: The 421 + Length of uri to invalidate * 2 = Content-Length
   content_length := LENGTH(uri)*2 + 421;

-- open connection
   c := utl_tcp.open_connection(machine, port); 

-- Send the HTP Protocol Header
-- send HTTP POST for DB Prism invalidator page
-- requires an pipeline setting like this
--   <map:match pattern="x-dbprism-cache-invalidate">
--    <map:generate type="serverpages" src="invalidate.xsp"/>
--    <map:serialize/>
--   </map:match>

   d := utl_tcp.write_line(c, 'POST /dbprism/x-dbprism-cache-invalidate HTTP/1.0');  

-- Note: The Authorization passes the User:Password as a base64 encoded
--       string. ie. administrator:123 =>  
   d := utl_tcp.write_line(c, 'Authorization: BASIC YWRtaW5pc3RyYXRvcjoxMjM=');  
   d := utl_tcp.write_line(c, 'Content-Length: ' || content_length);  
   dbms_output.put_line('Content-Length: ' || content_length); 

-- send TWO CR's per HTTP Protocol  (Note: One from above and the other sent by 
write_line)
-- (Note: If testing with telnet count cr as 2 characters)
   d := utl_tcp.write_line(c, '' );  

-- send DBPrism xml Invalidation message 
   d := utl_tcp.write_line(c, '<?xml version=' || DQUOTE || '1.0' || DQUOTE || '?>');

   d := utl_tcp.write_line(c, '<invalidation>');

   d := utl_tcp.write_line(c, '  <url exp=' || DQUOTE || '/cms/CMSj.content' || DQUOTE 
|| ' prefix=' || DQUOTE || 'no' || DQUOTE || '>');

   d := utl_tcp.write_line(c, '    <validity level=' || DQUOTE || '0' || DQUOTE || 
'/>');
   d := utl_tcp.write_line(c, '    <sitemap-argument name=' || DQUOTE || 'source' || 
DQUOTE || ' value=' || DQUOTE || uri || DQUOTE || '/>');
   d := utl_tcp.write_line(c, '    <sitemap-argument name=' || DQUOTE || 'printable' 
|| DQUOTE || ' value=' || DQUOTE || 'no' || DQUOTE || '/>');
   d := utl_tcp.write_line(c, '  </url>');
   d := utl_tcp.write_line(c, '  <url exp=' || DQUOTE || '/cms/CMSj.header' || DQUOTE 
|| ' prefix=' || DQUOTE || 'no' || DQUOTE || '>');

   d := utl_tcp.write_line(c, '    <validity level=' || DQUOTE || '0' || DQUOTE || 
'/>');
   d := utl_tcp.write_line(c, '    <sitemap-argument name=' || DQUOTE || 'source' || 
DQUOTE || ' value=' || DQUOTE || uri || DQUOTE || '/>');
   d := utl_tcp.write_line(c, '    <sitemap-argument name=' || DQUOTE || 'printable' 
|| DQUOTE || ' value=' || DQUOTE || 'no' || DQUOTE || '/>');
   d := utl_tcp.write_line(c, '  </url>');
   d := utl_tcp.write_line(c, '</invalidation>');
  utl_tcp.close_connection(c);
END;
/


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to