Ok, here's the patch.  The attached files apply to tc 3.3.  They 
allow tag handler pooling per the jsp spec.  The files come with
a few questions and comments.

Patch info:
----------
TagPoolManagerInterceptor.java should be placed in
src/facade22/org/apache/tomcat/facade

TagPoolManager.java
TagPoolManagerImpl.java
TagHandlerPool.java
TagHandlerPoolImpl.java
should be placed in src/share/org/apache/jasper/runtime

TagPoolManagerGenerator.java
TagPoolGenerator.java
should be placed in src/share/org/apache/jasper/runtime

The others are diffs.


Questions:
---------
1. Each web application wide TagPoolManager is stored in application scope
as an attribute.  Of course this means that an application could change it.
Is this acceptable?

2. Tag handlers are ALWAYS returned to the tag pool.  Even in the case of
exceptions, tag handlers will be reused.  Should tags be removed from the
pool if an exception is thrown during the normal set of tag calls (doStartTag,
doInitBody, etc.) ?


Caveats:
-------
1. Tag reuse has some important implications for the tag developer.
In general, the handler must be repeatedly usable without calls
to Tag.release.  For example, handlers should be sure to reset
certain variables to a well known state in doEndTag.  Only those
variables that change during the processing of the tag need to be
reset.  Those set via attribute setters (and not changed) are ok.

Note that some of the tags in the watchdog tests do not support
reuse.  So don't enable pooling for watchdog tests.

2. Because handlers are always returned to the pool, exceptions
may cause handlers to miss doEndTag and therefore possibly miss
cleanup / state reset.  The new TryCatchFinally interface fixes
this problem, but it's not available in jsp 1.1.


Comments would be appreciated (and would help my motivation toward
a 4.x patch :)  )

-Casey

TagEndGenerator.java.diff

modules.xml.diff

server.xml.diff

TagBeginGenerator.java.diff

JspParseEventListener.java.diff

/*
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */


package org.apache.tomcat.facade;

import org.apache.tomcat.core.*;
import org.apache.jasper.runtime.TagPoolManager;
import org.apache.jasper.runtime.TagPoolManagerImpl;

/**
 * This interceptor sets up tag pooling if it is enabled, it will
 * add a TagPoolManagerImpl to the application context.  JSPs will
 * then find it and use tag pooling.  To disable tag pooling, just
 * dont include this interceptor.
 *
 * @author Casey Lucas <[EMAIL PROTECTED]>
 * @see TagPoolManager
 */
public class TagPoolManagerInterceptor extends BaseInterceptor {

    /**
     * This hook is called when an application context is initialized.
     * Here, we add a TagPoolManagerImpl to the application context.
     *
     * @param ctx
     * @exception TomcatException
     */
    public synchronized void contextInit(Context ctx) throws TomcatException {
        if (debug>0) {
            log("Adding TagPoolManagerImpl: " + ctx);
        }
        TagPoolManager manager = (TagPoolManager) 
ctx.getAttribute(TagPoolManager.CONTEXT_ATTRIBUTE_NAME);
        if (manager != null) {
            if (debug>0) {
                log("TagPoolManagerImpl already exists for: " + ctx);
            }
        } else {
            manager = new TagPoolManagerImpl();
            ctx.setAttribute(TagPoolManager.CONTEXT_ATTRIBUTE_NAME, manager);
        }
    }

    /**
     * This hook is called when an application context is shutdown. Here,
     * the TagPoolManagerImpl is removed from the application context.
     *
     * @param ctx
     * @exception TomcatException
     */
    public synchronized void contextShutdown(Context ctx) throws TomcatException {
        if (debug>0) {
            log("Removing TagPoolManagerImpl: " + ctx);
        }
        TagPoolManager manager = (TagPoolManager) 
ctx.getAttribute(TagPoolManager.CONTEXT_ATTRIBUTE_NAME);
        if (manager != null) {
            ctx.removeAttribute(TagPoolManager.CONTEXT_ATTRIBUTE_NAME);
            manager.shutdown();
        } else {
            if (debug>0) {
                log("TagPoolManagerImpl not found for: " + ctx);
            }
        }
    }

}
/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.jasper.compiler;

import org.apache.jasper.runtime.TagPoolManager;

/**
 * This class generates code during the initilization phase that
 * declares and attempts to obtain a TagPoolManager.
 *
 * @author Casey Lucas <[EMAIL PROTECTED]>
 * @see TagPoolManager
 */
public class TagPoolManagerGenerator extends GeneratorBase
    implements InitMethodPhase {

    /**
     * variable name generated into java file
     */
    public static final String MANAGER_VARIABLE = "tagPoolManager";

    /**
     * Generate ref to TagPoolManager
     *
     * @param writer
     * @param phase
     */
    public void generate(ServletWriter writer, Class phase) {
        if (InitMethodPhase.class.isAssignableFrom(phase)) {
            writer.println("org.apache.jasper.runtime.TagPoolManager " + 
MANAGER_VARIABLE + " =");
            writer.pushIndent();
            // 
writer.println("org.apache.jasper.runtime.TagPoolManager.getDefaultPoolManager();");
            writer.println("(org.apache.jasper.runtime.TagPoolManager) 
getServletContext().getAttribute(\"" +
                TagPoolManager.CONTEXT_ATTRIBUTE_NAME + "\");");
            writer.popIndent();
        }
    }
}
/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.jasper.compiler;

import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import javax.servlet.jsp.tagext.TagLibraryInfo;
import javax.servlet.jsp.tagext.TagInfo;


/**
 * This class generates tag pooling related information.  Specifically,
 * it generates code to declare tag pools and to obtain tag pools
 * during jsp initialization.
 *
 * @author Casey Lucas <[EMAIL PROTECTED]>
 * @see TagPoolManager
 */
public class TagPoolGenerator extends GeneratorBase
    implements ClassDeclarationPhase, InitMethodPhase {

    // Tag related info.
    // Some of them aren't used now, but might be in the future.
    private String prefix;
    private String shortTagName;
    private TagLibraryInfo tli;
    private TagInfo ti;
    private Hashtable attrs;

    // Computed pool name and pool name as a valid variable name
    private String poolName;
    private String poolVarName;

    private final static String POOL_VARIABLE_NAME_PREFIX = "_jspx_tagPool_";
    /**
     * No default constructor.
     */
    private TagPoolGenerator() {
    }

    /**
     * Common constructor with enough information to generate code.
     *
     * @param prefix
     * @param shortTagName
     * @param attrs
     * @param tli
     * @param ti
     */
    public TagPoolGenerator(String prefix, String shortTagName,
                           Hashtable attrs, TagLibraryInfo tli,
                           TagInfo ti) {
        this.prefix = prefix;
        this.shortTagName = shortTagName;
        this.tli = tli;
        this.ti = ti;
        this.attrs = attrs;
        this.poolName = getPoolName(tli, ti, attrs);
        this.poolVarName = getPoolVariableName(poolName);
    }


    /**
     * This method returns a unique pool name based on the given
     * TagLibraryInfo, TagInfo, and set of tag attributes.  Tag
     * attribute order does not affect the returned name.
     *
     * @param tli
     * @param ti
     * @param attributes
     * @return
     */
    public static String getPoolName(TagLibraryInfo tli, TagInfo ti, Hashtable 
attributes) {
        return getSafeVariableName(tli.getURI() + "_" + ti.getTagName() + 
getStringFromAttributes(attributes));
    }


    /**
     * This method returns a unique pool variable name given
     * TagLibraryInfo, TagInfo and set of tag attributes.
     *
     * @param tli
     * @param ti
     * @param attributes
     * @return
     * @see getPoolName
     */
    public static String getPoolVariableName(TagLibraryInfo tli, TagInfo ti, Hashtable 
attributes) {
        return getPoolVariableName(getPoolName(tli, ti, attributes));
    }


    /**
     * This method returns a unique pool variable name given
     * a unique pool name
     *
     * @param poolName
     * @return
     * @see getPoolName
     */
    public static String getPoolVariableName(String poolName) {
        return getSafeVariableName(POOL_VARIABLE_NAME_PREFIX + poolName);
    }


    /**
     * This method generates code from based on the jsp.  During
     * class declaration phase, it declares a tag pool for this
     * tag.  During the initilization phase, it generates code
     * to lookup a pool from the tag pool manager.
     *
     * @param writer
     * @param phase
     */
    public void generate(ServletWriter writer, Class phase) {
        if (ClassDeclarationPhase.class.isAssignableFrom(phase)) {
            writer.println("org.apache.jasper.runtime.TagHandlerPool " + poolVarName + 
" = null;");
        } else if (InitMethodPhase.class.isAssignableFrom(phase)) {
            writer.println("if (" + TagPoolManagerGenerator.MANAGER_VARIABLE + " != 
null) {");
            writer.pushIndent();
            writer.println(poolVarName + " = ");
            writer.pushIndent();
            writer.println(TagPoolManagerGenerator.MANAGER_VARIABLE + ".getPool(\"" + 
poolName + "\",");
            writer.println(ti.getTagClassName() + ".class);");
            writer.popIndent();
            writer.popIndent();
            writer.println("}");
        }
    }


    /**
     * This method generates a string based on a set of tag attributes.
     * It sorts the attributes by name then concatenates them.
     *
     * @param attributes
     * @return
     */
    private static String getStringFromAttributes(Hashtable attributes) {
        if (attributes == null || attributes.isEmpty()) {
            return "";
        } else {
            Vector sortedAttributes = new Vector(attributes.size());

            Enumeration elements = attributes.keys();
            int i;
            while (elements.hasMoreElements()) {
                String attributeName = (String) elements.nextElement();
                for (i=0; i<sortedAttributes.size(); i++) {
                    if (attributeName.compareTo((String) 
sortedAttributes.elementAt(i)) < 0) {
                        break;
                    }
                }
                sortedAttributes.insertElementAt(attributeName, i);
            }

            // cat the attributes
            StringBuffer buffer = new StringBuffer();
            for (i=0; i<sortedAttributes.size(); i++) {
                buffer.append('_');
                buffer.append(sortedAttributes.elementAt(i));
            }

            return buffer.toString();
        }
    }


    /**
     * Constant that holds the characters that can be valid first
     * characters of a java variable.
     */
    private static final String VALID_FIRST_CHARS =
         "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";


    /**
     * Constant that holds the characters that can be used as in
     * a valid java variable name -- non first char case.
     */
    private static final String VALID_CHARS = VALID_FIRST_CHARS + "1234567890";


    /**
     * This method generates a string that can be used as a java
     * variable name.  Characters that cant be used are replaced
     * with an underscore.
     *
     * @param s
     * @return
     */
    private static String getSafeVariableName(String s) {
        StringBuffer buffer = new StringBuffer();
        String compareAgainst = VALID_FIRST_CHARS;
        for (int i=0; i<s.length(); i++) {
            if (i == 1) {
                compareAgainst = VALID_CHARS;
            }

            if (compareAgainst.indexOf(s.charAt(i)) != -1) {
                buffer.append(s.charAt(i));
            } else {
                buffer.append('_');
            }
        }

        return buffer.toString();
    }
}
/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.jasper.runtime;

import javax.servlet.jsp.tagext.Tag;

/**
 * This interface allows pooling of tag handlers.
 *
 * @author Casey Lucas <[EMAIL PROTECTED]>
 * @see TagPoolManager
 */
public interface TagHandlerPool {

    /**
     * This method is called by JSPs to obtain a tag handler.
     *
     * @return Tag handler appropriate for this pool
     */
    public Tag getHandler();

    /**
     * This method is called by JSPs when they are finished using a
     * tag handler obtained from getHandler
     *
     * @param usedTag
     */
    public void releaseHandler(Tag usedTag);

    /**
     * This method is called to shutdown this pool.  It is normally
     * called by TagPoolManager.shutdown.  It should perform cleanup
     * and call Tag.release for any stored tags.
     */
    public void shutdown();
}

/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.jasper.runtime;

import javax.servlet.jsp.tagext.Tag;
import java.util.Stack;
import java.util.EmptyStackException;
import java.util.Enumeration;
import org.apache.tomcat.util.log.Log;

/**
 * This class provides a basic implementation of TagHandlerPool.
 * Its pooling strategy is to grow the pool so that a caller
 * never has to wait for a tag handler.  Therefore in the worst
 * case, the pool size will be equal to the total number of
 * concurently used tags (that are at the same reuse scope.)  This
 * implementation does not shrink the pool.
 *
 * @author Casey Lucas <[EMAIL PROTECTED]>
 * @see TagPoolManagerImpl
 */
public class TagHandlerPoolImpl implements TagHandlerPool {

    /**
     * the class of tag handler that we store
     */
    Class myHandlerClass = null;
    /**
     * the collection of available handlers
     */
    Stack myHandlers = new Stack();

    /**
     * Tomcat logging mechanism
     */
    Log myLog = null;

    /**
     * Unique name for this pool
     * 
     * @see TagPoolGenerator
     */
    String myPoolName = null;

    /**
     * Keep this constructor private because we need to know what type
     * of handlers to create.
     */
    private TagHandlerPoolImpl() {
    }

    /**
     * Create a TagHandlerPoolImpl that will store objects of the given
     * class type
     *
     * @param handlerClass
     *               tag handler class
     */
    public TagHandlerPoolImpl(Class handlerClass, String poolName) {
        if (! Tag.class.isAssignableFrom(handlerClass)) {
            throw new IllegalArgumentException
                ("TagHandlerPoolImpl should only be used with Tag objects");
        }
        myHandlerClass = handlerClass;
        myPoolName = poolName;
        myLog = Log.getLog(TagPoolManagerImpl.LOG_NAME, this);
        if (myLog.getLevel() >= Log.INFORMATION) {
            myLog.log("New tag pool named '" + myPoolName + "' created to handle " +
                handlerClass.getName(), Log.INFORMATION);
        }
    }

    /**
     * Obtain a tag handler.  This implementation allocates one if one
     * is not available.  So the collection will grow with concurent
     * tag handler use.
     *
     * @return tag handler
     */
    public Tag getHandler() {
        Tag returnValue = null;

        try {
            synchronized (myHandlers) {
                if (myHandlers.empty()) {
                    if (myLog.getLevel() >= Log.DEBUG) {
                        myLog.log("Allocating new tag of type " +
                            myHandlerClass.getName(), Log.DEBUG);
                    }
                    returnValue = (Tag) myHandlerClass.newInstance();
                } else {
                    if (myLog.getLevel() >= Log.DEBUG) {
                        myLog.log("Returning cached tag of type " +
                            myHandlerClass.getName(), Log.DEBUG);
                    }
                    returnValue = (Tag) myHandlers.pop();
                }
            }
        }
        // Ignore these two errors.  The jsp page should get the same error
        // if it tries to allocate a tag handler.
        catch (InstantiationException exception) {
            if (myLog.getLevel() >= Log.WARNING) {
                myLog.log("Failed to allocate tag of type " + myHandlerClass.getName() 
+
                    ": " + exception.toString(), Log.WARNING);
            }
        }
        catch (IllegalAccessException exception) {
            if (myLog.getLevel() >= Log.WARNING) {
                myLog.log("Failed to allocate tag of type " + myHandlerClass.getName() 
+
                    ": " + exception.toString(), Log.WARNING);
            }
        }

        return returnValue;
    }


    /**
     * This method releases a tag handler obtained from getHandler.
     * The JSP shouls always call this method after finished using a
     * tag handler.
     *
     * @param usedTag tag previously obtained from getHandler
     */
    public void releaseHandler(Tag usedTag) {
        if (myLog.getLevel() >= Log.DEBUG) {
            myLog.log("Releasing tag of type " +
                myHandlerClass.getName(), Log.DEBUG);
        }
        synchronized (myHandlers) {
            myHandlers.push(usedTag);
        }
    }

    /**
     * This method performs pool shutdown.  It will call Tag.release
     * for all of its tag handlers.
     */
    public void shutdown() {
        synchronized (myHandlers) {
            if (myLog.getLevel() >= Log.INFORMATION) {
                myLog.log("Shutting down pool '" + myPoolName + "', pool contained " +
                    myHandlers.size() + " tags", Log.INFORMATION);
            }
            Enumeration handlers = myHandlers.elements();
            while (handlers.hasMoreElements()) {
                ((Tag) handlers.nextElement()).release();
            }
        }
    }
}

/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.jasper.runtime;


/**
 * This interface provides methods for tag handler pooling.
 * It specifies management of pools of tag handlers.  Normally,
 * one TagPoolManager derivative is stored per application
 * context.  This allows tag pooling on a per web application
 * scope.<br>
 *
 * TagPoolManagers manage TagHandlerPools.  TagHandlerPools
 * are uniquely named per reuse scope.  The current JSP spec
 * allows for tag reuse if all of these conditions are met:
 * <ul>
 * <li>tag scope doesnt conflict
 * <li>tags are of the same type
 * <li>tags use the same set of attributes
 * </ul>
 *
 * @author Casey Lucas <[EMAIL PROTECTED]>
 * @see TagPoolManagerInterceptor
 */
public interface TagPoolManager {

    /**
     * This constant is the name of the TagPoolManager attribute
     * stored into each ServletContext (if tag pooling is enabled.)
     */
    public static final String CONTEXT_ATTRIBUTE_NAME = 
"org.apache.jasper.runtime.TagPoolManager";

    /**
     * Obtain a named pool.  Each uniquely named pool holds tag
     * handlers.
     *
     * @param poolName unique name of the tag pool
     * @param handlerClass
     *                 the type of tag handler objects stored by the pool
     * @return
     */
    public TagHandlerPool getPool(String poolName, Class handlerClass);

    /**
     * This method allows the pool manager to shutdown all of its
     * pools.  Normally, this involves calling relase for all
     * its tag handlers.
     */
    public void shutdown();
}

/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.jasper.runtime;

import java.util.Hashtable;
import java.util.Enumeration;
import org.apache.tomcat.util.log.Log;

/**
 * This class provides a basic implementation for TagPoolManager.
 * It simply manages a collection of named pools, including their
 * retrieval and cleanup.
 *
 * @author Casey Lucas <[EMAIL PROTECTED]
 * @see TagPoolManagerInterceptor
 */
public class TagPoolManagerImpl implements TagPoolManager {

    /**
     * the collection of tag pools
     */
    Hashtable myPools = new Hashtable();

    /**
     * logging capabilities
     */
    Log myLog = null;


    /**
     * This constant is the log named that can be used in configuration
     * files to enable logging.
     */
    public static final String LOG_NAME = "tag_pool_log";


    /**
     * This constructor just sets up logging.
     */
    public TagPoolManagerImpl() {
        myLog = Log.getLog(LOG_NAME, this);
    }

    /**
     * Obtain a pool by the given name that provides handlers for
     * the given class.  If no pool is available for the given name
     * then allocate a new one and return it.
     *
     * @param poolName name of the requested pool
     * @param handlerClass
     *                 class of the tag handlers
     * @return named pool
     */
    public TagHandlerPool getPool(String poolName, Class handlerClass) {
        TagHandlerPool returnValue = null;
        synchronized (myPools) {
            returnValue = (TagHandlerPool) myPools.get(poolName);
            if (returnValue == null) {
                returnValue = new TagHandlerPoolImpl(handlerClass, poolName);
                myPools.put(poolName, returnValue);
            }

            if (myLog.getLevel() >= Log.INFORMATION) {
                myLog.log("Getting pool named '" +
                    poolName + "' for tag handler class '" +
                    handlerClass.getName() + "'", Log.INFORMATION);
                myLog.log("Number of pools is now " + myPools.size(), Log.INFORMATION);
            }
        }

        return returnValue;
    }


    /**
     * This method is called when the tag pools should be shutdown.  It
     * calls shutdown for each of the tag pools.
     */
    public void shutdown() {
        synchronized (myPools) {
            if (myLog.getLevel() >= Log.INFORMATION) {
                myLog.log("Shutting down " + myPools.size() + " pools", 
Log.INFORMATION);
            }

            Enumeration pools = myPools.elements();
            while (pools.hasMoreElements()) {
                ((TagHandlerPool) pools.nextElement()).shutdown();
            }
        }
    }

}

Reply via email to