[SCM] tomcat7: Servlet and JSP engine branch, upstream, updated. upstream/7.0.22

Miguel Landaeta miguel at miguel.cc
Tue Oct 4 23:08:02 UTC 2011


The following commit has been merged in the upstream branch:
commit 761f73ee75ab7852e2194fe111567fea425007ba
Author: Miguel Landaeta <miguel at miguel.cc>
Date:   Tue Oct 4 18:37:45 2011 -0430

    Imported Upstream version 7.0.22

diff --git a/build.properties.default b/build.properties.default
index 9951386..816a77b 100644
--- a/build.properties.default
+++ b/build.properties.default
@@ -21,13 +21,13 @@
 # modules that Tomcat depends on.  Copy this file to "build.properties"
 # in the top-level source directory, and customize it as needed.
 #
-# $Id: build.properties.default 1162976 2011-08-29 20:14:36Z markt $
+# $Id: build.properties.default 1176597 2011-09-27 20:24:31Z markt $
 # -----------------------------------------------------------------------------
 
 # ----- Version Control Flags -----
 version.major=7
 version.minor=0
-version.build=21
+version.build=22
 version.patch=0
 version.suffix=
 
diff --git a/build.xml b/build.xml
index 25a1fee..f1be936 100644
--- a/build.xml
+++ b/build.xml
@@ -1055,21 +1055,23 @@
 
   <target name="test" description="Runs the JUnit test cases"
           depends="test-bio,test-nio,test-apr" >
+    <fail if="test.result.error" message='Some tests completed with an Error. See ${tomcat.build}/logs for details, search for "FAILED".' />
+    <fail if="test.result.failure" message='Some tests completed with a Failure. See ${tomcat.build}/logs for details, search for "FAILED".' />
   </target>
   
-  <target name="test-bio" description="Runs the JUnit test cases for BIO"
+  <target name="test-bio" description="Runs the JUnit test cases for BIO. Does not stop on errors."
           depends="test-compile,deploy" if="${execute.test.bio}">
     <runtests protocol="org.apache.coyote.http11.Http11Protocol"
               extension=".BIO.txt" />
   </target>
   
-  <target name="test-nio" description="Runs the JUnit test cases for NIO"
+  <target name="test-nio" description="Runs the JUnit test cases for NIO. Does not stop on errors."
           depends="test-compile,deploy" if="${execute.test.nio}">
     <runtests protocol="org.apache.coyote.http11.Http11NioProtocol"
               extension=".NIO.txt" />
   </target>
   
-  <target name="test-apr" description="Runs the JUnit test cases for APR"
+  <target name="test-apr" description="Runs the JUnit test cases for APR. Does not stop on errors."
           depends="test-compile,deploy,test-apr-exists"
           if="${apr.exists}">
     <runtests protocol="org.apache.coyote.http11.Http11AprProtocol"
@@ -1082,14 +1084,18 @@
   </target>
 
   <macrodef name="runtests"
-            description="Runs the unit tests using the specified connector" >
+            description="Runs the unit tests using the specified connector.
+              Does not stop on errors, but sets 'test.result.error' and 'test.result.failure' properties.">
     <attribute name="protocol"
                description="The class name for the connector protocol"/>
     <attribute name="extension"
                description="The extension to use to distinguish the output"/>
 
     <sequential>
-      <junit printsummary="yes" fork="yes" dir="." showoutput="yes">
+      <junit printsummary="yes" fork="yes" dir="." showoutput="yes"
+        errorproperty="test.result.error"
+        failureproperty="test.result.failure"
+        haltonfailure="${test.haltonfailure}" >
 
         <jvmarg value="${test.jvmarg.egd}"/>
         <jvmarg value="-Djava.library.path=${test.apr.loc}"/>
@@ -1106,11 +1112,7 @@
 
         <!-- If test.entry is defined, run a single test, otherwise run all valid tests -->
         <test todir="${tomcat.build}/logs" name="${test.entry}" if="test.entry"/>
-        <batchtest todir="${tomcat.build}/logs"
-                   unless="test.entry"
-                   errorproperty="test.result.error"
-                   failureproperty="test.result.failure"
-                   haltonfailure="${test.haltonfailure}">
+        <batchtest todir="${tomcat.build}/logs" unless="test.entry">
           <fileset dir="test" >
             <!-- Include all by default -->
             <include name="${test.name}" />
@@ -1121,9 +1123,6 @@
           </fileset>
         </batchtest>
       </junit>
-
-      <fail if="test.result.error" message="Some tests completed with an Error. See ${tomcat.build}/logs for details." />
-      <fail if="test.result.failure" message="Some tests completed with a Failure. See ${tomcat.build}/logs for details." />
     </sequential>
   </macrodef>
 
diff --git a/conf/catalina.properties b/conf/catalina.properties
index e00d277..19ea25b 100644
--- a/conf/catalina.properties
+++ b/conf/catalina.properties
@@ -105,6 +105,7 @@ jmx-tools.jar,jta*.jar,log4j*.jar,mail*.jar,slf4j*.jar,\
 xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,\
 dnsns.jar,ldapsec.jar,localedata.jar,sunjce_provider.jar,sunmscapi.jar,\
 sunpkcs11.jar,jhall.jar,tools.jar,\
+sunec.jar,zipfs.jar,\
 apple_provider.jar,AppleScriptEngine.jar,CoreAudio.jar,dns_sd.jar,\
 j3daudio.jar,j3dcore.jar,j3dutils.jar,jai_core.jar,jai_codec.jar,\
 mlibwrapper_jai.jar,MRJToolkit.jar,vecmath.jar,\
diff --git a/java/javax/el/BeanELResolver.java b/java/javax/el/BeanELResolver.java
index ddaa8e2..307ba62 100644
--- a/java/javax/el/BeanELResolver.java
+++ b/java/javax/el/BeanELResolver.java
@@ -414,14 +414,16 @@ public class BeanELResolver extends ELResolver {
             }
             Method[] methods = clazz.getMethods();
             for (Method m : methods) {
-                if (methodName.equals(m.getName()) && 
-                        m.getParameterTypes().length == paramCount) {
-                    // Same number of parameters - use the first match
-                    matchingMethod = getMethod(clazz, m);
-                    break;
-                }
-                if (m.isVarArgs()) {
-                    matchingMethod = getMethod(clazz, m);
+                if (methodName.equals(m.getName())) {
+                    if (m.getParameterTypes().length == paramCount) {
+                        // Same number of parameters - use the first match
+                        matchingMethod = getMethod(clazz, m);
+                        break;
+                    }
+                    if (m.isVarArgs()
+                            && paramCount > m.getParameterTypes().length - 2) {
+                        matchingMethod = getMethod(clazz, m);
+                    }
                 }
             }
             if (matchingMethod == null) {
@@ -440,21 +442,21 @@ public class BeanELResolver extends ELResolver {
             if (matchingMethod.isVarArgs()) {
                 int varArgIndex = parameterTypes.length - 1;
                 // First argCount-1 parameters are standard
-                for (int i = 0; (i < varArgIndex - 1); i++) {
+                for (int i = 0; (i < varArgIndex); i++) {
                     parameters[i] = factory.coerceToType(params[i],
                             parameterTypes[i]);
                 }
-                // Last parameter is the varags
+                // Last parameter is the varargs
                 Class<?> varArgClass =
                     parameterTypes[varArgIndex].getComponentType();
+                final Object varargs = Array.newInstance(
+                    varArgClass,
+                    (paramCount - varArgIndex));
                 for (int i = (varArgIndex); i < paramCount; i++) {
-                    Object varargs = Array.newInstance(
-                            parameterTypes[paramCount],
-                            (paramCount - varArgIndex));
-                    Array.set(varargs, i,
+                    Array.set(varargs, i - varArgIndex,
                             factory.coerceToType(params[i], varArgClass));
-                    parameters[varArgIndex] = varargs;
                 }
+                parameters[varArgIndex] = varargs;
             } else {
                 parameters = new Object[parameterTypes.length];
                 for (int i = 0; i < parameterTypes.length; i++) {
diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java
index 47adac1..4806d05 100644
--- a/java/org/apache/catalina/Globals.java
+++ b/java/org/apache/catalina/Globals.java
@@ -23,7 +23,7 @@ package org.apache.catalina;
  * Global constants that are applicable to multiple packages within Catalina.
  *
  * @author Craig R. McClanahan
- * @version $Id: Globals.java 1087416 2011-03-31 19:33:04Z markt $
+ * @version $Id: Globals.java 1166689 2011-09-08 13:49:50Z markt $
  */
 
 public final class Globals {
@@ -98,9 +98,15 @@ public final class Globals {
      * for this SSL connection (as an object of type java.lang.String).
      */
     public static final String SSL_SESSION_ID_ATTR =
+        "javax.servlet.request.ssl_session_id";
+    /**
+     * Tomcat specific attribute as used in Tomcat 6.
+     * @deprecated
+     */
+    @Deprecated
+    public static final String SSL_SESSION_ID_TOMCAT_ATTR =
         "javax.servlet.request.ssl_session";
 
-
     /**
      * The request attribute key for the session manager.
      * This one is a Tomcat extension to the Servlet spec.
diff --git a/java/org/apache/catalina/Host.java b/java/org/apache/catalina/Host.java
index 16c9374..eecb8b8 100644
--- a/java/org/apache/catalina/Host.java
+++ b/java/org/apache/catalina/Host.java
@@ -40,7 +40,7 @@ import java.util.regex.Pattern;
  * of Context (representing an individual servlet context).
  *
  * @author Craig R. McClanahan
- * @version $Id: Host.java 1058357 2011-01-12 23:49:18Z markt $
+ * @version $Id: Host.java 1163999 2011-09-01 11:02:52Z markt $
  */
 
 public interface Host extends Container {
@@ -83,7 +83,7 @@ public interface Host extends Container {
      */
     public void setXmlBase(String xmlBase);
 
-        /**
+    /**
      * Return the application root for this Host.  This can be an absolute
      * pathname, a relative pathname, or a URL.
      */
diff --git a/java/org/apache/catalina/connector/CoyoteAdapter.java b/java/org/apache/catalina/connector/CoyoteAdapter.java
index 1c0cd85..fcf2177 100644
--- a/java/org/apache/catalina/connector/CoyoteAdapter.java
+++ b/java/org/apache/catalina/connector/CoyoteAdapter.java
@@ -57,7 +57,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: CoyoteAdapter.java 1158158 2011-08-16 08:58:35Z markt $
+ * @version $Id: CoyoteAdapter.java 1176592 2011-09-27 20:19:01Z markt $
  */
 public class CoyoteAdapter implements Adapter {
     
@@ -466,10 +466,8 @@ public class CoyoteAdapter implements Adapter {
 
         Request request = (Request) req.getNote(ADAPTER_NOTES);
         Response response = (Response) res.getNote(ADAPTER_NOTES);
-        boolean create = false;
         
         if (request == null) {
-            create = true;
             // Create objects
             request = connector.createRequest();
             request.setCoyoteRequest(req);
@@ -511,9 +509,7 @@ public class CoyoteAdapter implements Adapter {
         } catch (Throwable t) {
             ExceptionUtils.handleThrowable(t);
             log.warn(sm.getString("coyoteAdapter.accesslogFail"), t);
-        }
-        
-        if (create) {
+        } finally {
             request.recycle();
             response.recycle();
         }
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index c2872bd..5e6c2ae 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -100,7 +100,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Craig R. McClanahan
- * @version $Id: Request.java 1146005 2011-07-13 13:28:24Z markt $
+ * @version $Id: Request.java 1166689 2011-09-08 13:49:50Z markt $
  */
 
 public class Request
@@ -965,6 +965,7 @@ public class Request
             attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_ID_ATTR);
             if(attr != null) {
                 attributes.put(Globals.SSL_SESSION_ID_ATTR, attr);
+                attributes.put(Globals.SSL_SESSION_ID_TOMCAT_ATTR, attr);
             }
             attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_MGR_ATTR);
             if(attr != null) {
@@ -985,6 +986,7 @@ public class Request
             Globals.CIPHER_SUITE_ATTR.equals(name) ||
             Globals.KEY_SIZE_ATTR.equals(name)  ||
             Globals.SSL_SESSION_ID_ATTR.equals(name) ||
+            Globals.SSL_SESSION_ID_TOMCAT_ATTR.equals(name) ||
             Globals.SSL_SESSION_MGR_ATTR.equals(name);
     }
 
@@ -1003,6 +1005,8 @@ public class Request
      * <li>{@link Globals#CIPHER_SUITE_ATTR} (SSL connections only)</li>
      * <li>{@link Globals#KEY_SIZE_ATTR} (SSL connections only)</li>
      * <li>{@link Globals#SSL_SESSION_ID_ATTR} (SSL connections only)</li>
+     * <li>{@link Globals#SSL_SESSION_ID_TOMCAT_ATTR} (SSL connections only)
+     * </li>
      * <li>{@link Globals#SSL_SESSION_MGR_ATTR} (SSL connections only)</li>
      * </ul>
      * The underlying connector may also expose request attributes. These all
diff --git a/java/org/apache/catalina/core/ApplicationContextFacade.java b/java/org/apache/catalina/core/ApplicationContextFacade.java
index 56f2ae5..e7ade3d 100644
--- a/java/org/apache/catalina/core/ApplicationContextFacade.java
+++ b/java/org/apache/catalina/core/ApplicationContextFacade.java
@@ -27,7 +27,6 @@ import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
-import java.util.EnumSet;
 import java.util.Enumeration;
 import java.util.EventListener;
 import java.util.HashMap;
@@ -56,7 +55,7 @@ import org.apache.tomcat.util.ExceptionUtils;
  *
  * @author Remy Maucherat
  * @author Jean-Francois Arcand
- * @version $Id: ApplicationContextFacade.java 1104557 2011-05-17 20:57:46Z kkolinko $
+ * @version $Id: ApplicationContextFacade.java 1166080 2011-09-07 09:24:40Z markt $
  */
 
 public class ApplicationContextFacade implements ServletContext {
@@ -118,7 +117,7 @@ public class ApplicationContextFacade implements ServletContext {
         classCache.put("getRealPath", clazz);
         classCache.put("getAttribute", clazz);
         classCache.put("log", clazz);
-        classCache.put("setSessionTrackingModes", new Class[]{EnumSet.class} );
+        classCache.put("setSessionTrackingModes", new Class[]{Set.class} );
     }
 
 
@@ -571,7 +570,7 @@ public class ApplicationContextFacade implements ServletContext {
     @SuppressWarnings("unchecked") // doPrivileged() returns the correct type
     public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
         if (SecurityUtil.isPackageProtectionEnabled()) {
-            return (EnumSet<SessionTrackingMode>)
+            return (Set<SessionTrackingMode>)
                 doPrivileged("getDefaultSessionTrackingModes", null);
         } else {
             return context.getDefaultSessionTrackingModes();
@@ -582,7 +581,7 @@ public class ApplicationContextFacade implements ServletContext {
     @SuppressWarnings("unchecked") // doPrivileged() returns the correct type
     public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
         if (SecurityUtil.isPackageProtectionEnabled()) {
-            return (EnumSet<SessionTrackingMode>)
+            return (Set<SessionTrackingMode>)
                 doPrivileged("getEffectiveSessionTrackingModes", null);
         } else {
             return context.getEffectiveSessionTrackingModes();
diff --git a/java/org/apache/catalina/core/DefaultInstanceManager.java b/java/org/apache/catalina/core/DefaultInstanceManager.java
index 1d1fed7..6f3ce03 100644
--- a/java/org/apache/catalina/core/DefaultInstanceManager.java
+++ b/java/org/apache/catalina/core/DefaultInstanceManager.java
@@ -21,6 +21,8 @@ package org.apache.catalina.core;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -29,8 +31,12 @@ import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.WeakHashMap;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
@@ -52,7 +58,7 @@ import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
- * @version $Id: DefaultInstanceManager.java 1145981 2011-07-13 12:45:57Z markt $
+ * @version $Id: DefaultInstanceManager.java 1176588 2011-09-27 20:13:32Z markt $
  */
 public class DefaultInstanceManager implements InstanceManager {
 
@@ -65,6 +71,8 @@ public class DefaultInstanceManager implements InstanceManager {
     private Properties restrictedFilters = new Properties();
     private Properties restrictedListeners = new Properties();
     private Properties restrictedServlets = new Properties();
+    private final Map<Class<?>,WeakReference<List<AnnotationCacheEntry>>> annotationCache =
+        new WeakHashMap<Class<?>, WeakReference<List<AnnotationCacheEntry>>>();
 
     public DefaultInstanceManager(Context context, Map<String, Map<String, String>> injectionMap, org.apache.catalina.Context catalinaContext, ClassLoader containerClassLoader) {
         classLoader = catalinaContext.getLoader().getClassLoader();
@@ -134,6 +142,7 @@ public class DefaultInstanceManager implements InstanceManager {
     private Object newInstance(Object instance, Class<?> clazz) throws IllegalAccessException, InvocationTargetException, NamingException {
         if (!ignoreAnnotations) {
             Map<String, String> injections = injectionMap.get(clazz.getName());
+            populateAnnotationsCache(clazz, injections);
             processAnnotations(instance, injections);
             postConstruct(instance, clazz);
         }
@@ -158,46 +167,33 @@ public class DefaultInstanceManager implements InstanceManager {
      */
     protected void postConstruct(Object instance, final Class<?> clazz)
             throws IllegalAccessException, InvocationTargetException {
+        if (context == null) {
+            // No resource injection
+            return;
+        }
+
         Class<?> superClass = clazz.getSuperclass();
         if (superClass != Object.class) {
             postConstruct(instance, superClass);
         }
 
-        Method[] methods = null;
-        if (Globals.IS_SECURITY_ENABLED) {
-            methods = AccessController.doPrivileged(
-                    new PrivilegedAction<Method[]>(){
-                @Override
-                public Method[] run(){
-                    return clazz.getDeclaredMethods();
-                }
-            });
-        } else {
-            methods = clazz.getDeclaredMethods();
-        }
-        Method postConstruct = null;
-        for (Method method : methods) {
-            if (method.isAnnotationPresent(PostConstruct.class)) {
-                if ((postConstruct != null)
-                        || (method.getParameterTypes().length != 0)
-                        || (Modifier.isStatic(method.getModifiers()))
-                        || (method.getExceptionTypes().length > 0)
-                        || (!method.getReturnType().getName().equals("void"))) {
-                    throw new IllegalArgumentException("Invalid PostConstruct annotation");
-                }
-                postConstruct = method;
-            }
-        }
-
         // At the end the postconstruct annotated
         // method is invoked
-        if (postConstruct != null) {
-            boolean accessibility = postConstruct.isAccessible();
-            postConstruct.setAccessible(true);
-            postConstruct.invoke(instance);
-            postConstruct.setAccessible(accessibility);
+        List<AnnotationCacheEntry> annotations;
+        synchronized (annotationCache) {
+            annotations = annotationCache.get(clazz).get();
+        }
+        for (AnnotationCacheEntry entry : annotations) {
+            if (entry.getType() == AnnotationCacheEntryType.POST_CONSTRUCT) {
+                Method postConstruct = (Method) entry.getAccessibleObject();
+                boolean accessibility = postConstruct.isAccessible();
+                synchronized (postConstruct) {
+                    postConstruct.setAccessible(true);
+                    postConstruct.invoke(instance);
+                    postConstruct.setAccessible(accessibility);
+                }
+            }
         }
-
     }
 
 
@@ -217,41 +213,222 @@ public class DefaultInstanceManager implements InstanceManager {
             preDestroy(instance, superClass);
         }
 
-        Method[] methods;
-        if (Globals.IS_SECURITY_ENABLED) {
-            methods = AccessController.doPrivileged(
-                    new PrivilegedAction<Method[]>(){
-                @Override
-                public Method[] run(){
-                    return clazz.getDeclaredMethods();
-                }
-            });
-        } else {
-            methods = clazz.getDeclaredMethods();
-        }
-        Method preDestroy = null;
-        for (Method method : methods) {
-            if (method.isAnnotationPresent(PreDestroy.class)) {
-                if ((method.getParameterTypes().length != 0)
-                        || (Modifier.isStatic(method.getModifiers()))
-                        || (method.getExceptionTypes().length > 0)
-                        || (!method.getReturnType().getName().equals("void"))) {
-                    throw new IllegalArgumentException("Invalid PreDestroy annotation");
+        // At the end the postconstruct annotated
+        // method is invoked
+        List<AnnotationCacheEntry> annotations = null;
+        synchronized (annotationCache) {
+            WeakReference<List<AnnotationCacheEntry>> ref =
+                annotationCache.get(clazz);
+            if (ref != null) {
+                annotations = ref.get();
+            }
+        }
+        if (annotations == null) {
+            // instance not created through the instance manager
+            return;
+        }
+        for (AnnotationCacheEntry entry : annotations) {
+            if (entry.getType() == AnnotationCacheEntryType.PRE_DESTROY) {
+                Method preDestroy = (Method) entry.getAccessibleObject();
+                boolean accessibility = preDestroy.isAccessible();
+                synchronized (preDestroy) {
+                    preDestroy.setAccessible(true);
+                    preDestroy.invoke(instance);
+                    preDestroy.setAccessible(accessibility);
                 }
-                preDestroy = method;
-                break;
             }
         }
+    }
 
-        // At the end the postconstruct annotated
-        // method is invoked
-        if (preDestroy != null) {
-            boolean accessibility = preDestroy.isAccessible();
-            preDestroy.setAccessible(true);
-            preDestroy.invoke(instance);
-            preDestroy.setAccessible(accessibility);
+
+    /**
+     * Make sure that the annotations cache has been populated for the provided
+     * class.
+     *
+     * @param clazz         clazz to populate annotations for
+     * @param injections    map of injections for this class from xml deployment
+     *                      descriptor
+     * @throws IllegalAccessException       if injection target is inaccessible
+     * @throws javax.naming.NamingException if value cannot be looked up in jndi
+     * @throws java.lang.reflect.InvocationTargetException
+     *                                      if injection fails
+     */
+    protected void populateAnnotationsCache(Class<?> clazz,
+            Map<String, String> injections) throws IllegalAccessException,
+            InvocationTargetException, NamingException {
+
+        if (context == null) {
+            // No resource injection
+            return;
         }
 
+        while (clazz != null) {
+            List<AnnotationCacheEntry> annotations = null;
+            synchronized (annotationCache) {
+                WeakReference<List<AnnotationCacheEntry>> ref =
+                    annotationCache.get(clazz);
+                if (ref != null) {
+                    annotations = ref.get();
+                }
+            }
+            if (annotations == null) {
+                annotations = new ArrayList<AnnotationCacheEntry>();
+                // Initialize fields annotations
+                Field[] fields = null;
+                if (Globals.IS_SECURITY_ENABLED) {
+                    final Class<?> clazz2 = clazz;
+                    fields = AccessController.doPrivileged(
+                            new PrivilegedAction<Field[]>(){
+                        @Override
+                        public Field[] run(){
+                            return clazz2.getDeclaredFields();
+                        }
+                    });
+                } else {
+                    fields = clazz.getDeclaredFields();
+                }
+                for (Field field : fields) {
+                    if (injections != null && injections.containsKey(field.getName())) {
+                        annotations.add(new AnnotationCacheEntry(field,
+                                injections.get(field.getName()),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (field.isAnnotationPresent(Resource.class)) {
+                        Resource annotation = field.getAnnotation(Resource.class);
+                        annotations.add(new AnnotationCacheEntry(field,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (field.isAnnotationPresent(EJB.class)) {
+                        EJB annotation = field.getAnnotation(EJB.class);
+                        annotations.add(new AnnotationCacheEntry(field,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (field.isAnnotationPresent(WebServiceRef.class)) {
+                        WebServiceRef annotation =
+                                field.getAnnotation(WebServiceRef.class);
+                        annotations.add(new AnnotationCacheEntry(field,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (field.isAnnotationPresent(PersistenceContext.class)) {
+                        PersistenceContext annotation =
+                                field.getAnnotation(PersistenceContext.class);
+                        annotations.add(new AnnotationCacheEntry(field,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (field.isAnnotationPresent(PersistenceUnit.class)) {
+                        PersistenceUnit annotation =
+                                field.getAnnotation(PersistenceUnit.class);
+                        annotations.add(new AnnotationCacheEntry(field,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    }
+                }
+        
+                // Initialize methods annotations
+                Method[] methods = null;
+                if (Globals.IS_SECURITY_ENABLED) {
+                    final Class<?> clazz2 = clazz;
+                    methods = AccessController.doPrivileged(
+                            new PrivilegedAction<Method[]>(){
+                        @Override
+                        public Method[] run(){
+                            return clazz2.getDeclaredMethods();
+                        }
+                    });
+                } else {
+                    methods = clazz.getDeclaredMethods();
+                }
+                Method postConstruct = null;
+                Method preDestroy = null;
+                for (Method method : methods) {
+                    String methodName = method.getName();
+                    if (injections != null && methodName.startsWith("set") && methodName.length() > 3) {
+                        String fieldName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
+                        if (injections.containsKey(fieldName)) {
+                            annotations.add(new AnnotationCacheEntry(method,
+                                    injections.get(method.getName()),
+                                    AnnotationCacheEntryType.FIELD));
+                            break;
+                        }
+                    }
+                    if (method.isAnnotationPresent(Resource.class)) {
+                        Resource annotation = method.getAnnotation(Resource.class);
+                        annotations.add(new AnnotationCacheEntry(method,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (method.isAnnotationPresent(EJB.class)) {
+                        EJB annotation = method.getAnnotation(EJB.class);
+                        annotations.add(new AnnotationCacheEntry(method,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (method.isAnnotationPresent(WebServiceRef.class)) {
+                        WebServiceRef annotation =
+                                method.getAnnotation(WebServiceRef.class);
+                        annotations.add(new AnnotationCacheEntry(method,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (method.isAnnotationPresent(PersistenceContext.class)) {
+                        PersistenceContext annotation =
+                                method.getAnnotation(PersistenceContext.class);
+                        annotations.add(new AnnotationCacheEntry(method,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    } else if (method.isAnnotationPresent(PersistenceUnit.class)) {
+                        PersistenceUnit annotation =
+                                method.getAnnotation(PersistenceUnit.class);
+                        annotations.add(new AnnotationCacheEntry(method,
+                                annotation.name(),
+                                AnnotationCacheEntryType.FIELD));
+                    }
+
+                    if (method.isAnnotationPresent(PostConstruct.class)) {
+                        if ((postConstruct != null) ||
+                                (method.getParameterTypes().length != 0) ||
+                                (Modifier.isStatic(method.getModifiers())) ||
+                                (method.getExceptionTypes().length > 0) ||
+                                (!method.getReturnType().getName().equals("void"))) {
+                            throw new IllegalArgumentException(
+                                    "Invalid PostConstruct annotation");
+                        }
+                        postConstruct = method;
+                    }
+                    
+                    if (method.isAnnotationPresent(PreDestroy.class)) {
+                        if ((preDestroy != null ||
+                                method.getParameterTypes().length != 0) ||
+                                (Modifier.isStatic(method.getModifiers())) ||
+                                (method.getExceptionTypes().length > 0) ||
+                                (!method.getReturnType().getName().equals("void"))) {
+                            throw new IllegalArgumentException(
+                                    "Invalid PreDestroy annotation");
+                        }
+                        preDestroy = method;
+                    }
+                }
+                if (postConstruct != null) {
+                    annotations.add(new AnnotationCacheEntry(postConstruct,
+                            null, AnnotationCacheEntryType.POST_CONSTRUCT));
+                }
+                if (preDestroy != null) {
+                    annotations.add(new AnnotationCacheEntry(preDestroy,
+                            null, AnnotationCacheEntryType.PRE_DESTROY));
+                }
+                if (annotations.size() == 0) {
+                    // Use common empty list to save memory 
+                    annotations = Collections.emptyList();
+                }
+                synchronized (annotationCache) {
+                    annotationCache.put(clazz,
+                            new WeakReference<List<AnnotationCacheEntry>>(
+                                    annotations));
+                }
+            } else {
+                // If the annotations for this class have been cached, the
+                // annotations for all the super classes will have been cachced
+                // as well
+                break;
+            }
+            clazz = clazz.getSuperclass();
+        }
     }
 
 
@@ -276,102 +453,35 @@ public class DefaultInstanceManager implements InstanceManager {
         Class<?> clazz = instance.getClass();
         
         while (clazz != null) {
-            // Initialize fields annotations
-            Field[] fields = null;
-            if (Globals.IS_SECURITY_ENABLED) {
-                final Class<?> clazz2 = clazz;
-                fields = AccessController.doPrivileged(
-                        new PrivilegedAction<Field[]>(){
-                    @Override
-                    public Field[] run(){
-                        return clazz2.getDeclaredFields();
-                    }
-                });
-            } else {
-                fields = clazz.getDeclaredFields();
+            List<AnnotationCacheEntry> annotations;
+            synchronized (annotationCache) {
+                annotations = annotationCache.get(clazz).get();
             }
-            for (Field field : fields) {
-                if (injections != null && injections.containsKey(field.getName())) {
-                    lookupFieldResource(context, instance, field,
-                            injections.get(field.getName()), clazz);
-                } else if (field.isAnnotationPresent(Resource.class)) {
-                    Resource annotation = field.getAnnotation(Resource.class);
-                    lookupFieldResource(context, instance, field,
-                            annotation.name(), clazz);
-                } else if (field.isAnnotationPresent(EJB.class)) {
-                    EJB annotation = field.getAnnotation(EJB.class);
-                    lookupFieldResource(context, instance, field,
-                            annotation.name(), clazz);
-                } else if (field.isAnnotationPresent(WebServiceRef.class)) {
-                    WebServiceRef annotation =
-                            field.getAnnotation(WebServiceRef.class);
-                    lookupFieldResource(context, instance, field,
-                            annotation.name(), clazz);
-                } else if (field.isAnnotationPresent(PersistenceContext.class)) {
-                    PersistenceContext annotation =
-                            field.getAnnotation(PersistenceContext.class);
-                    lookupFieldResource(context, instance, field,
-                            annotation.name(), clazz);
-                } else if (field.isAnnotationPresent(PersistenceUnit.class)) {
-                    PersistenceUnit annotation =
-                            field.getAnnotation(PersistenceUnit.class);
-                    lookupFieldResource(context, instance, field,
-                            annotation.name(), clazz);
-                }
-            }
-    
-            // Initialize methods annotations
-            Method[] methods = null;
-            if (Globals.IS_SECURITY_ENABLED) {
-                final Class<?> clazz2 = clazz;
-                methods = AccessController.doPrivileged(
-                        new PrivilegedAction<Method[]>(){
-                    @Override
-                    public Method[] run(){
-                        return clazz2.getDeclaredMethods();
+            for (AnnotationCacheEntry entry : annotations) {
+                if (entry.getType() == AnnotationCacheEntryType.FIELD) {
+                    if (entry.getAccessibleObject() instanceof Method) {
+                        lookupMethodResource(context, instance,
+                                (Method) entry.getAccessibleObject(),
+                                entry.getName(), clazz);
+                    } else {
+                        lookupFieldResource(context, instance,
+                                (Field) entry.getAccessibleObject(),
+                                entry.getName(), clazz);
                     }
-                });
-            } else {
-                methods = clazz.getDeclaredMethods();
-            }
-            for (Method method : methods) {
-                String methodName = method.getName();
-                if (injections != null && methodName.startsWith("set") && methodName.length() > 3) {
-                    String fieldName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
-                    if (injections.containsKey(fieldName)) {
-                        lookupMethodResource(context, instance, method,
-                                injections.get(fieldName), clazz);
-                        break;
-                    }
-                }
-                if (method.isAnnotationPresent(Resource.class)) {
-                    Resource annotation = method.getAnnotation(Resource.class);
-                    lookupMethodResource(context, instance, method,
-                            annotation.name(), clazz);
-                } else if (method.isAnnotationPresent(EJB.class)) {
-                    EJB annotation = method.getAnnotation(EJB.class);
-                    lookupMethodResource(context, instance, method,
-                            annotation.name(), clazz);
-                } else if (method.isAnnotationPresent(WebServiceRef.class)) {
-                    WebServiceRef annotation =
-                            method.getAnnotation(WebServiceRef.class);
-                    lookupMethodResource(context, instance, method,
-                            annotation.name(), clazz);
-                } else if (method.isAnnotationPresent(PersistenceContext.class)) {
-                    PersistenceContext annotation =
-                            method.getAnnotation(PersistenceContext.class);
-                    lookupMethodResource(context, instance, method,
-                            annotation.name(), clazz);
-                } else if (method.isAnnotationPresent(PersistenceUnit.class)) {
-                    PersistenceUnit annotation =
-                            method.getAnnotation(PersistenceUnit.class);
-                    lookupMethodResource(context, instance, method,
-                            annotation.name(), clazz);
                 }
             }
             clazz = clazz.getSuperclass();
         }
+    }
+
 
+    /**
+     * Makes cache size available to unit tests.
+     */
+    protected int getAnnotationCacheSize() {
+        synchronized (annotationCache) {
+            return annotationCache.size();
+        }
     }
 
 
@@ -420,6 +530,10 @@ public class DefaultInstanceManager implements InstanceManager {
         if (Filter.class.isAssignableFrom(clazz)) {
             checkAccess(clazz, restrictedFilters);
         } else if (Servlet.class.isAssignableFrom(clazz)) {
+            if (ContainerServlet.class.isAssignableFrom(clazz)) {
+                throw new SecurityException("Restricted (ContainerServlet) " +
+                        clazz);
+            }
             checkAccess(clazz, restrictedServlets);
         } else {
             checkAccess(clazz, restrictedListeners);
@@ -464,9 +578,11 @@ public class DefaultInstanceManager implements InstanceManager {
         }
 
         accessibility = field.isAccessible();
-        field.setAccessible(true);
-        field.set(instance, lookedupResource);
-        field.setAccessible(accessibility);
+        synchronized (field) {
+            field.setAccessible(true);
+            field.set(instance, lookedupResource);
+            field.setAccessible(accessibility);
+        }
     }
 
     /**
@@ -506,9 +622,11 @@ public class DefaultInstanceManager implements InstanceManager {
         }
 
         accessibility = method.isAccessible();
-        method.setAccessible(true);
-        method.invoke(instance, lookedupResource);
-        method.setAccessible(accessibility);
+        synchronized (method) {
+            method.setAccessible(true);
+            method.invoke(instance, lookedupResource);
+            method.setAccessible(accessibility);
+        }
     }
 
     public static String getName(Method setter) {
@@ -529,4 +647,32 @@ public class DefaultInstanceManager implements InstanceManager {
         }
         return jndiName;
     }
+
+    private static final class AnnotationCacheEntry {
+        private final AccessibleObject accessibleObject;
+        private final String name;
+        private final AnnotationCacheEntryType type;
+
+        public AnnotationCacheEntry(AccessibleObject accessibleObject,
+                String name, AnnotationCacheEntryType type) {
+            this.accessibleObject = accessibleObject;
+            this.name = name;
+            this.type = type;
+        }
+
+        public AccessibleObject getAccessibleObject() {
+            return accessibleObject;
+        }
+
+        public String getName() {
+            return name;
+        }
+        public AnnotationCacheEntryType getType() {
+            return type;
+        }
+    }
+
+    private static enum AnnotationCacheEntryType {
+        FIELD, POST_CONSTRUCT, PRE_DESTROY
+    }
 }
diff --git a/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java b/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
index 37b13e8..22b0a48 100644
--- a/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
+++ b/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
@@ -24,6 +24,7 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.sql.DriverManager;
+import java.util.StringTokenizer;
 
 import javax.imageio.ImageIO;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -81,6 +82,19 @@ public class JreMemoryLeakPreventionListener implements LifecycleListener {
     }
 
     /**
+     * Protect against the memory leak caused when the
+     * <code>sun.java2d.Disposer</code> class is loaded by a web application.
+     * Defaults to <code>false</code> because a new Thread is launched.
+     */
+    private boolean java2dDisposerProtection = false;
+    public boolean isJava2DDisposerProtection() {
+        return java2dDisposerProtection;
+    }
+    public void setJava2DDisposerProtection(boolean java2dDisposerProtection) {
+        this.java2dDisposerProtection = java2dDisposerProtection;
+    }
+
+    /**
      * Protect against the memory leak caused when the first call to
      * <code>sun.misc.GC.requestLatency(long)</code> is triggered by a web
      * application. This first call will start a GC Daemon thread with the
@@ -189,7 +203,21 @@ public class JreMemoryLeakPreventionListener implements LifecycleListener {
     public void setDriverManagerProtection(boolean driverManagerProtection) {
         this.driverManagerProtection = driverManagerProtection;
     }
-
+    
+    /**
+     * List of comma-separated fully qualified class names to load and initialize during
+     * the startup of this Listener. This allows to pre-load classes that are known to 
+     * provoke classloader leaks if they are loaded during a request processing.
+     */
+    private String classesToInitialize = null;
+    public String getClassesToInitialize() {
+        return classesToInitialize;
+    }
+    public void setClassesToInitialize(String classesToInitialize) {
+        this.classesToInitialize = classesToInitialize;
+    }
+    
+    
     @Override
     public void lifecycleEvent(LifecycleEvent event) {
         // Initialise these classes when Tomcat starts
@@ -237,6 +265,18 @@ public class JreMemoryLeakPreventionListener implements LifecycleListener {
                   java.awt.Toolkit.getDefaultToolkit();
                 }
 
+                // Trigger the creation of the "Java2D Disposer" thread.
+                // See https://issues.apache.org/bugzilla/show_bug.cgi?id=51687
+                if(java2dDisposerProtection) {
+                    try {
+                        Class.forName("sun.java2d.Disposer");
+                    }
+                    catch (ClassNotFoundException cnfe) {
+                        // Ignore this case: we must be running on a
+                        // non-Sun-based JRE.
+                    }
+                }
+
                 /*
                  * Several components end up calling:
                  * sun.misc.GC.requestLatency(long)
@@ -394,6 +434,22 @@ public class JreMemoryLeakPreventionListener implements LifecycleListener {
                         }
                     }
                 }
+                
+                if (classesToInitialize != null) {
+                    StringTokenizer strTok =
+                        new StringTokenizer(classesToInitialize, ", \r\n\t");
+                    while (strTok.hasMoreTokens()) {
+                        String classNameToLoad = strTok.nextToken();
+                        try {
+                            Class.forName(classNameToLoad);
+                        } catch (ClassNotFoundException e) {
+                            log.error(
+                                sm.getString("jreLeakListener.classToInitializeFail",
+                                    classNameToLoad), e);
+                            // continue with next class to load
+                        }
+                    }
+                }
 
             } finally {
                 Thread.currentThread().setContextClassLoader(loader);
diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties
index 5581523..839005c 100644
--- a/java/org/apache/catalina/core/LocalStrings.properties
+++ b/java/org/apache/catalina/core/LocalStrings.properties
@@ -83,6 +83,7 @@ jreLeakListener.jarUrlConnCacheFail=Failed to disable Jar URL connection caching
 jreLeakListener.xmlParseFail=Error whilst attempting to prevent memory leaks during XML parsing
 jreLeakListener.authPolicyFail=Error whilst attempting to prevent memory leak in javax.security.auth.Policy class
 jreLeakListener.ldapPoolManagerFail=Failed to trigger creation of the com.sun.jndi.ldap.LdapPoolManager class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs.
+jreLeakListener.classToInitializeFail=Failed to load class {0} during Tomcat start to prevent possible memory leaks.
 naming.wsdlFailed=Failed to find wsdl file: {0}
 naming.bindFailed=Failed to bind object: {0}
 naming.jmxRegistrationFailed=Failed to register in JMX: {0}
diff --git a/java/org/apache/catalina/core/StandardContextValve.java b/java/org/apache/catalina/core/StandardContextValve.java
index da3bc83..f8917e2 100644
--- a/java/org/apache/catalina/core/StandardContextValve.java
+++ b/java/org/apache/catalina/core/StandardContextValve.java
@@ -21,24 +21,16 @@ package org.apache.catalina.core;
 
 import java.io.IOException;
 
-import javax.servlet.DispatcherType;
 import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.catalina.Container;
-import org.apache.catalina.Context;
 import org.apache.catalina.Wrapper;
 import org.apache.catalina.comet.CometEvent;
-import org.apache.catalina.connector.ClientAbortException;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
-import org.apache.catalina.deploy.ErrorPage;
 import org.apache.catalina.valves.ValveBase;
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.buf.MessageBytes;
 
 /**
@@ -49,13 +41,11 @@ import org.apache.tomcat.util.buf.MessageBytes;
  * when processing HTTP requests.
  *
  * @author Craig R. McClanahan
- * @version $Id: StandardContextValve.java 1157904 2011-08-15 16:36:27Z markt $
+ * @version $Id: StandardContextValve.java 1164481 2011-09-02 11:30:56Z markt $
  */
 
 final class StandardContextValve extends ValveBase {
     
-    private static final Log log = LogFactory.getLog(StandardHostValve.class);
-
     //------------------------------------------------------ Constructor
     public StandardContextValve() {
         super(true);
@@ -124,7 +114,7 @@ final class StandardContextValve extends ValveBase {
                 || (requestPathMB.equalsIgnoreCase("/META-INF"))
                 || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
                 || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
-            error(request, response, HttpServletResponse.SC_NOT_FOUND);
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
             return;
         }
 
@@ -151,13 +141,13 @@ final class StandardContextValve extends ValveBase {
         // Select the Wrapper to be used for this Request
         Wrapper wrapper = request.getWrapper();
         if (wrapper == null) {
-            error(request, response, HttpServletResponse.SC_NOT_FOUND);
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
             return;
         } else if (wrapper.isUnavailable()) {
             // May be as a result of a reload, try and find the new wrapper
             wrapper = (Wrapper) container.findChild(wrapper.getName());
             if (wrapper == null) {
-                error(request, response, HttpServletResponse.SC_NOT_FOUND);
+                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                 return;
             }
         }
@@ -169,47 +159,14 @@ final class StandardContextValve extends ValveBase {
             container.getLogger().error(sm.getString(
                     "standardContextValve.acknowledgeException"), ioe);
             request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
-            error(request, response,
-                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
             return;
         }
         
-        // Don't fire listeners during async processing
-        // If a request init listener throws an exception, the request is
-        // aborted
-        boolean asyncAtStart = request.isAsync(); 
-        if (asyncAtStart || context.fireRequestInitEvent(request)) {
-            if (request.isAsyncSupported()) {
-                request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
-            }
-            wrapper.getPipeline().getFirst().invoke(request, response);
-
-            // If the request was async at the start and an error occurred then
-            // the async error handling will kick-in and that will fire the
-            // request destroyed event *after* the error handling has taken
-            // place
-            if (!(request.isAsync() || (asyncAtStart && request.getAttribute(
-                        RequestDispatcher.ERROR_EXCEPTION) != null))) {
-                // Protect against NPEs if context was destroyed during a long
-                // running request.
-                StandardContext c = context;
-                if (c != null && c.getState().isAvailable()) {
-                    // Error page processing
-                    response.setSuspended(false);
-
-                    Throwable t = (Throwable) request.getAttribute(
-                            RequestDispatcher.ERROR_EXCEPTION);
-
-                    if (t != null) {
-                        throwable(request, response, t);
-                    } else {
-                        status(request, response);
-                    }
-
-                    context.fireRequestDestroyEvent(request);
-                }
-            }
+        if (request.isAsyncSupported()) {
+            request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
         }
+        wrapper.getPipeline().getFirst().invoke(request, response);
     }
 
 
@@ -233,273 +190,5 @@ final class StandardContextValve extends ValveBase {
         Wrapper wrapper = request.getWrapper();
 
         wrapper.getPipeline().getFirst().event(request, response, event);
-            
-        // Error page processing
-        response.setSuspended(false);
-
-        Throwable t = (Throwable) request.getAttribute(
-                RequestDispatcher.ERROR_EXCEPTION);
-
-        if (t != null) {
-            throwable(request, response, t);
-        } else {
-            status(request, response);
-        }
-    }
-
-
-    // -------------------------------------------------------- Private Methods
-
-
-    /**
-     * Report an error for the specified resource.
-     *
-     * @param response The response we are creating
-     */
-    private void error(Request request, Response response, int status) {
-
-        context.fireRequestInitEvent(request);
-        
-        try {
-            response.sendError(status);
-        } catch (IllegalStateException e) {
-            // Ignore
-        } catch (IOException e) {
-            // Ignore
-        }
-
-        response.setSuspended(false);
-        status(request, response);
-        
-        context.fireRequestDestroyEvent(request);
-    }
-
-
-    /**
-     * Handle the HTTP status code (and corresponding message) generated
-     * while processing the specified Request to produce the specified
-     * Response.  Any exceptions that occur during generation of the error
-     * report are logged and swallowed.
-     *
-     * @param request The request being processed
-     * @param response The response being generated
-     */
-    private void status(Request request, Response response) {
-
-        int statusCode = response.getStatus();
-
-        // Handle a custom error page for this status code
-        Context context = request.getContext();
-        if (context == null)
-            return;
-
-        /* Only look for error pages when isError() is set.
-         * isError() is set when response.sendError() is invoked. This
-         * allows custom error pages without relying on default from
-         * web.xml.
-         */
-        if (!response.isError())
-            return;
-
-        ErrorPage errorPage = context.findErrorPage(statusCode);
-        if (errorPage != null) {
-            response.setAppCommitted(false);
-            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
-                              Integer.valueOf(statusCode));
-
-            String message = response.getMessage();
-            if (message == null)
-                message = "";
-            request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
-            request.setAttribute
-                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
-                 errorPage.getLocation());
-            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-                              DispatcherType.ERROR);
-
-
-            Wrapper wrapper = request.getWrapper();
-            if (wrapper != null)
-                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
-                                  wrapper.getName());
-            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
-                                 request.getRequestURI());
-            if (custom(request, response, errorPage)) {
-                try {
-                    response.flushBuffer();
-                } catch (ClientAbortException e) {
-                    // Ignore
-                } catch (IOException e) {
-                    container.getLogger().warn("Exception Processing " + errorPage, e);
-                }
-            }
-        }
-    }
-
-    
-    /**
-     * Handle the specified Throwable encountered while processing
-     * the specified Request to produce the specified Response.  Any
-     * exceptions that occur during generation of the exception report are
-     * logged and swallowed.
-     *
-     * @param request The request being processed
-     * @param response The response being generated
-     * @param throwable The exception that occurred (which possibly wraps
-     *  a root cause exception
-     */
-    private void throwable(Request request, Response response,
-                             Throwable throwable) {
-        Context context = request.getContext();
-        if (context == null)
-            return;
-
-        Throwable realError = throwable;
-
-        if (realError instanceof ServletException) {
-            realError = ((ServletException) realError).getRootCause();
-            if (realError == null) {
-                realError = throwable;
-            }
-        }
-
-        // If this is an aborted request from a client just log it and return
-        if (realError instanceof ClientAbortException ) {
-            if (log.isDebugEnabled()) {
-                log.debug
-                    (sm.getString("standardHost.clientAbort",
-                        realError.getCause().getMessage()));
-            }
-            return;
-        }
-
-        ErrorPage errorPage = findErrorPage(context, throwable);
-        if ((errorPage == null) && (realError != throwable)) {
-            errorPage = findErrorPage(context, realError);
-        }
-
-        if (errorPage != null) {
-            response.setAppCommitted(false);
-            request.setAttribute
-                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
-                 errorPage.getLocation());
-            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-                              DispatcherType.ERROR);
-            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
-                    new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
-            request.setAttribute(RequestDispatcher.ERROR_MESSAGE,
-                              throwable.getMessage());
-            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,
-                              realError);
-            Wrapper wrapper = request.getWrapper();
-            if (wrapper != null)
-                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
-                                  wrapper.getName());
-            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
-                                 request.getRequestURI());
-            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,
-                              realError.getClass());
-            if (custom(request, response, errorPage)) {
-                try {
-                    response.flushBuffer();
-                } catch (IOException e) {
-                    container.getLogger().warn("Exception Processing " + errorPage, e);
-                }
-            }
-        } else {
-            // A custom error-page has not been defined for the exception
-            // that was thrown during request processing. Check if an
-            // error-page for error code 500 was specified and if so,
-            // send that page back as the response.
-            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            // The response is an error
-            response.setError();
-
-            status(request, response);
-        }
-    }
-
-
-    /**
-     * Handle an HTTP status code or Java exception by forwarding control
-     * to the location included in the specified errorPage object.  It is
-     * assumed that the caller has already recorded any request attributes
-     * that are to be forwarded to this page.  Return <code>true</code> if
-     * we successfully utilized the specified error page location, or
-     * <code>false</code> if the default error report should be rendered.
-     *
-     * @param request The request being processed
-     * @param response The response being generated
-     * @param errorPage The errorPage directive we are obeying
-     */
-    private boolean custom(Request request, Response response,
-                             ErrorPage errorPage) {
-
-        if (container.getLogger().isDebugEnabled())
-            container.getLogger().debug("Processing " + errorPage);
-
-        request.setPathInfo(errorPage.getLocation());
-
-        try {
-            // Forward control to the specified location
-            ServletContext servletContext =
-                request.getContext().getServletContext();
-            RequestDispatcher rd =
-                servletContext.getRequestDispatcher(errorPage.getLocation());
-
-            if (response.isCommitted()) {
-                // Response is committed - including the error page is the
-                // best we can do 
-                rd.include(request.getRequest(), response.getResponse());
-            } else {
-                // Reset the response (keeping the real error code and message)
-                response.resetBuffer(true);
-
-                rd.forward(request.getRequest(), response.getResponse());
-
-                // If we forward, the response is suspended again
-                response.setSuspended(false);
-            }
-
-            // Indicate that we have successfully processed this custom page
-            return (true);
-
-        } catch (Throwable t) {
-            ExceptionUtils.handleThrowable(t);
-            // Report our failure to process this custom page
-            container.getLogger().error("Exception Processing " + errorPage, t);
-            return (false);
-
-        }
-    }
-
-    
-    /**
-     * Find and return the ErrorPage instance for the specified exception's
-     * class, or an ErrorPage instance for the closest superclass for which
-     * there is such a definition.  If no associated ErrorPage instance is
-     * found, return <code>null</code>.
-     *
-     * @param context The Context in which to search
-     * @param exception The exception for which to find an ErrorPage
-     */
-    private static ErrorPage findErrorPage
-        (Context context, Throwable exception) {
-
-        if (exception == null)
-            return (null);
-        Class<?> clazz = exception.getClass();
-        String name = clazz.getName();
-        while (!Object.class.equals(clazz)) {
-            ErrorPage errorPage = context.findErrorPage(name);
-            if (errorPage != null)
-                return (errorPage);
-            clazz = clazz.getSuperclass();
-            if (clazz == null)
-                break;
-            name = clazz.getName();
-        }
-        return (null);
-
     }
 }
diff --git a/java/org/apache/catalina/core/StandardHostValve.java b/java/org/apache/catalina/core/StandardHostValve.java
index 1b58672..5d1a18c 100644
--- a/java/org/apache/catalina/core/StandardHostValve.java
+++ b/java/org/apache/catalina/core/StandardHostValve.java
@@ -23,15 +23,24 @@ import java.io.IOException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.catalina.Context;
 import org.apache.catalina.Globals;
+import org.apache.catalina.Wrapper;
 import org.apache.catalina.comet.CometEvent;
+import org.apache.catalina.connector.ClientAbortException;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.ErrorPage;
 import org.apache.catalina.valves.ValveBase;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.res.StringManager;
 
 
@@ -44,11 +53,13 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: StandardHostValve.java 1157904 2011-08-15 16:36:27Z markt $
+ * @version $Id: StandardHostValve.java 1164482 2011-09-02 11:33:05Z markt $
  */
 
 final class StandardHostValve extends ValveBase {
 
+    private static final Log log = LogFactory.getLog(StandardHostValve.class);
+
     protected static final boolean STRICT_SERVLET_COMPLIANCE;
 
     protected static final boolean ACCESS_SESSION;
@@ -146,9 +157,46 @@ final class StandardHostValve extends ValveBase {
             request.setAsyncSupported(context.getPipeline().isAsyncSupported());
         }
 
-
-        // Ask this Context to process this request
-        context.getPipeline().getFirst().invoke(request, response);
+        // Don't fire listeners during async processing
+        // If a request init listener throws an exception, the request is
+        // aborted
+        boolean asyncAtStart = request.isAsync(); 
+        if (asyncAtStart || context.fireRequestInitEvent(request)) {
+
+            // Ask this Context to process this request
+            try {
+                context.getPipeline().getFirst().invoke(request, response);
+            } catch (Throwable t) {
+                ExceptionUtils.handleThrowable(t);
+                request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
+                throwable(request, response, t);
+            }
+    
+            // If the request was async at the start and an error occurred then
+            // the async error handling will kick-in and that will fire the
+            // request destroyed event *after* the error handling has taken
+            // place
+            if (!(request.isAsync() || (asyncAtStart && request.getAttribute(
+                        RequestDispatcher.ERROR_EXCEPTION) != null))) {
+                // Protect against NPEs if context was destroyed during a long
+                // running request.
+                if (context.getState().isAvailable()) {
+                    // Error page processing
+                    response.setSuspended(false);
+    
+                    Throwable t = (Throwable) request.getAttribute(
+                            RequestDispatcher.ERROR_EXCEPTION);
+    
+                    if (t != null) {
+                        throwable(request, response, t);
+                    } else {
+                        status(request, response);
+                    }
+    
+                    context.fireRequestDestroyEvent(request);
+                }
+            }
+        }
 
         // Access a session (if present) to update last accessed time, based on a
         // strict interpretation of the specification
@@ -165,7 +213,6 @@ final class StandardHostValve extends ValveBase {
             Thread.currentThread().setContextClassLoader
                     (StandardHostValve.class.getClassLoader());
         }
-
     }
 
 
@@ -197,6 +244,19 @@ final class StandardHostValve extends ValveBase {
         // Ask this Context to process this request
         context.getPipeline().getFirst().event(request, response, event);
 
+        
+        // Error page processing
+        response.setSuspended(false);
+
+        Throwable t = (Throwable) request.getAttribute(
+                RequestDispatcher.ERROR_EXCEPTION);
+
+        if (t != null) {
+            throwable(request, response, t);
+        } else {
+            status(request, response);
+        }
+
         // Access a session (if present) to update last accessed time, based on a
         // strict interpretation of the specification
         if (ACCESS_SESSION) {
@@ -210,6 +270,237 @@ final class StandardHostValve extends ValveBase {
     }
 
 
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Handle the HTTP status code (and corresponding message) generated
+     * while processing the specified Request to produce the specified
+     * Response.  Any exceptions that occur during generation of the error
+     * report are logged and swallowed.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     */
+    private void status(Request request, Response response) {
+
+        int statusCode = response.getStatus();
+
+        // Handle a custom error page for this status code
+        Context context = request.getContext();
+        if (context == null)
+            return;
+
+        /* Only look for error pages when isError() is set.
+         * isError() is set when response.sendError() is invoked. This
+         * allows custom error pages without relying on default from
+         * web.xml.
+         */
+        if (!response.isError())
+            return;
+
+        ErrorPage errorPage = context.findErrorPage(statusCode);
+        if (errorPage != null) {
+            response.setAppCommitted(false);
+            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
+                              Integer.valueOf(statusCode));
+
+            String message = response.getMessage();
+            if (message == null)
+                message = "";
+            request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
+            request.setAttribute
+                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+                 errorPage.getLocation());
+            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                              DispatcherType.ERROR);
+
+
+            Wrapper wrapper = request.getWrapper();
+            if (wrapper != null)
+                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
+                                  wrapper.getName());
+            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
+                                 request.getRequestURI());
+            if (custom(request, response, errorPage)) {
+                try {
+                    response.flushBuffer();
+                } catch (ClientAbortException e) {
+                    // Ignore
+                } catch (IOException e) {
+                    container.getLogger().warn("Exception Processing " + errorPage, e);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Handle the specified Throwable encountered while processing
+     * the specified Request to produce the specified Response.  Any
+     * exceptions that occur during generation of the exception report are
+     * logged and swallowed.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     * @param throwable The exception that occurred (which possibly wraps
+     *  a root cause exception
+     */
+    private void throwable(Request request, Response response,
+                             Throwable throwable) {
+        Context context = request.getContext();
+        if (context == null)
+            return;
+
+        Throwable realError = throwable;
+
+        if (realError instanceof ServletException) {
+            realError = ((ServletException) realError).getRootCause();
+            if (realError == null) {
+                realError = throwable;
+            }
+        }
+
+        // If this is an aborted request from a client just log it and return
+        if (realError instanceof ClientAbortException ) {
+            if (log.isDebugEnabled()) {
+                log.debug
+                    (sm.getString("standardHost.clientAbort",
+                        realError.getCause().getMessage()));
+            }
+            return;
+        }
+
+        ErrorPage errorPage = findErrorPage(context, throwable);
+        if ((errorPage == null) && (realError != throwable)) {
+            errorPage = findErrorPage(context, realError);
+        }
+
+        if (errorPage != null) {
+            response.setAppCommitted(false);
+            request.setAttribute
+                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+                 errorPage.getLocation());
+            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                              DispatcherType.ERROR);
+            request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
+                    new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
+            request.setAttribute(RequestDispatcher.ERROR_MESSAGE,
+                              throwable.getMessage());
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,
+                              realError);
+            Wrapper wrapper = request.getWrapper();
+            if (wrapper != null)
+                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,
+                                  wrapper.getName());
+            request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
+                                 request.getRequestURI());
+            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,
+                              realError.getClass());
+            if (custom(request, response, errorPage)) {
+                try {
+                    response.flushBuffer();
+                } catch (IOException e) {
+                    container.getLogger().warn("Exception Processing " + errorPage, e);
+                }
+            }
+        } else {
+            // A custom error-page has not been defined for the exception
+            // that was thrown during request processing. Check if an
+            // error-page for error code 500 was specified and if so,
+            // send that page back as the response.
+            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            // The response is an error
+            response.setError();
+
+            status(request, response);
+        }
+    }
+
+
+    /**
+     * Handle an HTTP status code or Java exception by forwarding control
+     * to the location included in the specified errorPage object.  It is
+     * assumed that the caller has already recorded any request attributes
+     * that are to be forwarded to this page.  Return <code>true</code> if
+     * we successfully utilized the specified error page location, or
+     * <code>false</code> if the default error report should be rendered.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     * @param errorPage The errorPage directive we are obeying
+     */
+    private boolean custom(Request request, Response response,
+                             ErrorPage errorPage) {
+
+        if (container.getLogger().isDebugEnabled())
+            container.getLogger().debug("Processing " + errorPage);
+
+        request.setPathInfo(errorPage.getLocation());
+
+        try {
+            // Forward control to the specified location
+            ServletContext servletContext =
+                request.getContext().getServletContext();
+            RequestDispatcher rd =
+                servletContext.getRequestDispatcher(errorPage.getLocation());
+
+            if (response.isCommitted()) {
+                // Response is committed - including the error page is the
+                // best we can do 
+                rd.include(request.getRequest(), response.getResponse());
+            } else {
+                // Reset the response (keeping the real error code and message)
+                response.resetBuffer(true);
+
+                rd.forward(request.getRequest(), response.getResponse());
+
+                // If we forward, the response is suspended again
+                response.setSuspended(false);
+            }
+
+            // Indicate that we have successfully processed this custom page
+            return (true);
+
+        } catch (Throwable t) {
+            ExceptionUtils.handleThrowable(t);
+            // Report our failure to process this custom page
+            container.getLogger().error("Exception Processing " + errorPage, t);
+            return (false);
+
+        }
+    }
+
+
+    /**
+     * Find and return the ErrorPage instance for the specified exception's
+     * class, or an ErrorPage instance for the closest superclass for which
+     * there is such a definition.  If no associated ErrorPage instance is
+     * found, return <code>null</code>.
+     *
+     * @param context The Context in which to search
+     * @param exception The exception for which to find an ErrorPage
+     */
+    private static ErrorPage findErrorPage
+        (Context context, Throwable exception) {
+
+        if (exception == null)
+            return (null);
+        Class<?> clazz = exception.getClass();
+        String name = clazz.getName();
+        while (!Object.class.equals(clazz)) {
+            ErrorPage errorPage = context.findErrorPage(name);
+            if (errorPage != null)
+                return (errorPage);
+            clazz = clazz.getSuperclass();
+            if (clazz == null)
+                break;
+            name = clazz.getName();
+        }
+        return (null);
+
+    }
+
+
     private static class PrivilegedSetTccl implements PrivilegedAction<Void> {
 
         private ClassLoader cl;
diff --git a/java/org/apache/catalina/ha/session/BackupManager.java b/java/org/apache/catalina/ha/session/BackupManager.java
index 2d0a53a..26c3d7d 100644
--- a/java/org/apache/catalina/ha/session/BackupManager.java
+++ b/java/org/apache/catalina/ha/session/BackupManager.java
@@ -24,7 +24,6 @@ import org.apache.catalina.DistributedManager;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.LifecycleState;
 import org.apache.catalina.Session;
-import org.apache.catalina.ha.CatalinaCluster;
 import org.apache.catalina.ha.ClusterManager;
 import org.apache.catalina.ha.ClusterMessage;
 import org.apache.catalina.tribes.Channel;
@@ -53,15 +52,6 @@ public class BackupManager extends ClusterManagerBase
     protected String name;
 
     /**
-     * A reference to the cluster
-     */
-    protected CatalinaCluster cluster;
-    
-    /**
-     * Should listeners be notified?
-     */
-    private boolean notifyListenersOnReplication;
-    /**
      * 
      */
     private int mapSendOptions = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK|Channel.SEND_OPTIONS_USE_ACK;
@@ -93,13 +83,6 @@ public class BackupManager extends ClusterManagerBase
         mExpireSessionsOnShutdown = expireSessionsOnShutdown;
     }
 
-    @Override
-    public void setCluster(CatalinaCluster cluster) {
-        if(log.isDebugEnabled())
-            log.debug("Cluster associated with BackupManager");
-        this.cluster = cluster;
-    }
-
     public boolean getExpireSessionsOnShutdown()
     {
         return mExpireSessionsOnShutdown;
@@ -160,9 +143,8 @@ public class BackupManager extends ClusterManagerBase
 
         try {
             cluster.registerManager(this);
-            CatalinaCluster catclust = cluster;
             LazyReplicatedMap map = new LazyReplicatedMap(this,
-                                                          catclust.getChannel(),
+                                                          cluster.getChannel(),
                                                           rpcTimeout,
                                                           getMapName(),
                                                           getClassLoaders());
@@ -176,8 +158,7 @@ public class BackupManager extends ClusterManagerBase
     }
     
     public String getMapName() {
-        CatalinaCluster catclust = cluster;
-        String name = catclust.getManagerName(getName(),this)+"-"+"map";
+        String name = cluster.getManagerName(getName(),this)+"-"+"map";
         if ( log.isDebugEnabled() ) log.debug("Backup manager, Setting map name to:"+name);
         return name;
     }
@@ -219,26 +200,11 @@ public class BackupManager extends ClusterManagerBase
     public void setName(String name) {
         this.name = name;
     }
-    @Override
-    public boolean isNotifyListenersOnReplication() {
-        return notifyListenersOnReplication;
-    }
-    public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) {
-        this.notifyListenersOnReplication = notifyListenersOnReplication;
-    }
 
     public void setMapSendOptions(int mapSendOptions) {
         this.mapSendOptions = mapSendOptions;
     }
 
-    /* 
-     * @see org.apache.catalina.ha.ClusterManager#getCluster()
-     */
-    @Override
-    public CatalinaCluster getCluster() {
-        return cluster;
-    }
-
     public int getMapSendOptions() {
         return mapSendOptions;
     }
@@ -259,12 +225,9 @@ public class BackupManager extends ClusterManagerBase
     @Override
     public ClusterManager cloneFromTemplate() {
         BackupManager result = new BackupManager();
+        clone(result);
         result.mExpireSessionsOnShutdown = mExpireSessionsOnShutdown;
-        result.name = "Clone-from-"+name;
-        result.cluster = cluster;
-        result.notifyListenersOnReplication = notifyListenersOnReplication;
         result.mapSendOptions = mapSendOptions;
-        result.maxActiveSessions = maxActiveSessions;
         result.rpcTimeout = rpcTimeout;
         return result;
     }
diff --git a/java/org/apache/catalina/ha/session/ClusterManagerBase.java b/java/org/apache/catalina/ha/session/ClusterManagerBase.java
index dcdec13..ff5b08d 100644
--- a/java/org/apache/catalina/ha/session/ClusterManagerBase.java
+++ b/java/org/apache/catalina/ha/session/ClusterManagerBase.java
@@ -19,9 +19,11 @@ package org.apache.catalina.ha.session;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.util.regex.Pattern;
 
 import org.apache.catalina.Container;
 import org.apache.catalina.Loader;
+import org.apache.catalina.ha.CatalinaCluster;
 import org.apache.catalina.ha.ClusterManager;
 import org.apache.catalina.session.ManagerBase;
 import org.apache.catalina.tribes.io.ReplicationStream;
@@ -29,12 +31,101 @@ import org.apache.catalina.tribes.io.ReplicationStream;
 /**
  * 
  * @author Filip Hanik
- * @version $Id: ClusterManagerBase.java 1026793 2010-10-24 13:25:36Z markt $
+ * @version $Id: ClusterManagerBase.java 1175159 2011-09-24 11:16:50Z rjung $
  */
 
 public abstract class ClusterManagerBase extends ManagerBase
         implements ClusterManager {
 
+    /**
+     * A reference to the cluster
+     */
+    protected CatalinaCluster cluster = null;
+
+    /**
+     * Should listeners be notified?
+     */
+    private boolean notifyListenersOnReplication = true;
+
+    /**
+     * The pattern used for including session attributes to
+     *  replication, e.g. <code>^(userName|sessionHistory)$</code>.
+     *  If not set, all session attributes will be eligible for replication.
+     */
+    private String sessionAttributeFilter = null;
+
+    /**
+     * The compiled pattern used for including session attributes to
+     * replication, e.g. <code>^(userName|sessionHistory)$</code>.
+     * If not set, all session attributes will be eligible for replication.
+     */
+    private Pattern sessionAttributePattern = null;
+
+    /* 
+     * @see org.apache.catalina.ha.ClusterManager#getCluster()
+     */
+    @Override
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    @Override
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+
+    @Override
+    public boolean isNotifyListenersOnReplication() {
+        return notifyListenersOnReplication;
+    }
+
+    public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) {
+        this.notifyListenersOnReplication = notifyListenersOnReplication;
+    }
+
+    /**
+     * Return the string pattern used for including session attributes
+     * to replication.
+     *
+     * @return the sessionAttributeFilter
+     */
+    public String getSessionAttributeFilter() {
+        return sessionAttributeFilter;
+    }
+
+    /**
+     * Set the pattern used for including session attributes to replication.
+     * If not set, all session attributes will be eligible for replication.
+     * <p>
+     * E.g. <code>^(userName|sessionHistory)$</code>
+     * </p>
+     *
+     * @param sessionAttributeFilter
+     *            the filter name pattern to set
+     */
+    public void setSessionAttributeFilter(String sessionAttributeFilter) {
+        if (sessionAttributeFilter == null
+            || sessionAttributeFilter.trim().equals("")) {
+            this.sessionAttributeFilter = null;
+            sessionAttributePattern = null;
+        } else {
+            this.sessionAttributeFilter = sessionAttributeFilter;
+            sessionAttributePattern = Pattern.compile(sessionAttributeFilter);
+        }
+    }
+
+    /**
+     * Check whether the given session attribute should be distributed
+     *
+     * @return true if the attribute should be distributed
+     */
+    public boolean willAttributeDistribute(String name) {
+        if (sessionAttributePattern == null) {
+            return true;
+        }
+        return sessionAttributePattern.matcher(name).matches();
+    }
+
     public static ClassLoader[] getClassLoaders(Container container) {
         Loader loader = null;
         ClassLoader classLoader = null;
@@ -88,4 +179,13 @@ public abstract class ClusterManagerBase extends ManagerBase
     public void unload() {
         // NOOP
     }
-}
\ No newline at end of file
+
+    protected void clone(ClusterManagerBase copy) {
+        copy.setName("Clone-from-" + getName());
+        copy.setCluster(getCluster());
+        copy.maxActiveSessions = getMaxActiveSessions();
+        copy.setNotifyListenersOnReplication(isNotifyListenersOnReplication());
+        copy.setSessionAttributeFilter(getSessionAttributeFilter());
+    }
+
+}
diff --git a/java/org/apache/catalina/ha/session/DeltaManager.java b/java/org/apache/catalina/ha/session/DeltaManager.java
index 9feb1a2..868d80c 100644
--- a/java/org/apache/catalina/ha/session/DeltaManager.java
+++ b/java/org/apache/catalina/ha/session/DeltaManager.java
@@ -62,7 +62,7 @@ import org.apache.tomcat.util.res.StringManager;
  * @author Craig R. McClanahan
  * @author Jean-Francois Arcand
  * @author Peter Rossbach
- * @version $Id: DeltaManager.java 1141441 2011-06-30 08:39:53Z kfujino $
+ * @version $Id: DeltaManager.java 1174181 2011-09-22 15:01:08Z rjung $
  */
 
 public class DeltaManager extends ClusterManagerBase{
@@ -87,7 +87,6 @@ public class DeltaManager extends ClusterManagerBase{
      */
     protected static String managerName = "DeltaManager";
     protected String name = null;
-    private CatalinaCluster cluster = null;
 
     /**
      * cached replication valve cluster container!
@@ -95,7 +94,6 @@ public class DeltaManager extends ClusterManagerBase{
     private volatile ReplicationValve replicationValve = null ;
     
     private boolean expireSessionsOnShutdown = false;
-    private boolean notifyListenersOnReplication = true;
     private boolean notifySessionListenersOnReplication = true;
     private boolean notifyContainerListenersOnReplication  = true;
     private volatile boolean stateTransfered = false ;
@@ -412,15 +410,6 @@ public class DeltaManager extends ClusterManagerBase{
         this.expireSessionsOnShutdown = expireSessionsOnShutdown;
     }
     
-    @Override
-    public boolean isNotifyListenersOnReplication() {
-        return notifyListenersOnReplication;
-    }
-
-    public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) {
-        this.notifyListenersOnReplication = notifyListenersOnReplication;
-    }
-
     public boolean isNotifyContainerListenersOnReplication() {
         return notifyContainerListenersOnReplication;
     }
@@ -430,16 +419,6 @@ public class DeltaManager extends ClusterManagerBase{
         this.notifyContainerListenersOnReplication = notifyContainerListenersOnReplication;
     }
     
-    @Override
-    public CatalinaCluster getCluster() {
-        return cluster;
-    }
-
-    @Override
-    public void setCluster(CatalinaCluster cluster) {
-        this.cluster = cluster;
-    }
-
     // --------------------------------------------------------- Public Methods
 
     /**
@@ -1340,7 +1319,7 @@ public class DeltaManager extends ClusterManagerBase{
             try {
                 session.lock();
                 DeltaRequest dreq = deserializeDeltaRequest(session, delta);
-                dreq.execute(session, notifyListenersOnReplication);
+                dreq.execute(session, isNotifyListenersOnReplication());
                 session.setPrimarySession(false);
             }finally {
                 session.unlock();
@@ -1500,12 +1479,9 @@ public class DeltaManager extends ClusterManagerBase{
     @Override
     public ClusterManager cloneFromTemplate() {
         DeltaManager result = new DeltaManager();
-        result.name = "Clone-from-"+name;
-        result.cluster = cluster;
+        clone(result);
         result.replicationValve = replicationValve;
-        result.maxActiveSessions = maxActiveSessions;
         result.expireSessionsOnShutdown = expireSessionsOnShutdown;
-        result.notifyListenersOnReplication = notifyListenersOnReplication;
         result.notifySessionListenersOnReplication = notifySessionListenersOnReplication;
         result.notifyContainerListenersOnReplication = notifyContainerListenersOnReplication;
         result.stateTransferTimeout = stateTransferTimeout;
diff --git a/java/org/apache/catalina/ha/session/DeltaSession.java b/java/org/apache/catalina/ha/session/DeltaSession.java
index 9182fd6..7e5174f 100644
--- a/java/org/apache/catalina/ha/session/DeltaSession.java
+++ b/java/org/apache/catalina/ha/session/DeltaSession.java
@@ -53,7 +53,7 @@ import org.apache.tomcat.util.res.StringManager;
  * track of deltas during a request.
  *
  * @author Filip Hanik
- * @version $Id: DeltaSession.java 1135069 2011-06-13 09:44:33Z kfujino $
+ * @version $Id: DeltaSession.java 1175194 2011-09-24 16:32:19Z rjung $
  */
 
 public class DeltaSession extends StandardSession implements Externalizable,ClusterSession,ReplicatedMapEntry {
@@ -559,6 +559,37 @@ public class DeltaSession extends StandardSession implements Externalizable,Clus
 
 
     /**
+     * Check whether the Object can be distributed.
+     * The object is always distributable, if the cluster manager
+     * decides to never distribute it.
+     * @param name The name of the attribute to check
+     * @param value The value of the attribute to check
+     * @return true if the attribute is distributable, false otherwise
+     */
+    @Override
+    protected boolean isAttributeDistributable(String name, Object value) {
+        if (manager instanceof ClusterManagerBase &&
+            !((ClusterManagerBase)manager).willAttributeDistribute(name))
+            return true;
+        return super.isAttributeDistributable(name, value);
+    }
+
+    /**
+     * Exclude attributes from replication.
+     * @param name the attribute's name
+     * @return true if attribute should not be replicated
+     */
+    @Override
+    protected boolean exclude(String name) {
+
+        if (super.exclude(name))
+            return true;
+        if (manager instanceof ClusterManagerBase)
+            return !((ClusterManagerBase)manager).willAttributeDistribute(name);
+        return false;
+    }
+
+    /**
      * Remove the object bound with the specified name from this session. If the
      * session does not have an object bound with this name, this method does
      * nothing.
@@ -635,6 +666,7 @@ public class DeltaSession extends StandardSession implements Externalizable,Clus
 
     // -------------------------------------------- HttpSession Private Methods
 
+
     /**
      * Read a serialized version of this session object from the specified
      * object input stream.
diff --git a/java/org/apache/catalina/loader/WebappClassLoader.java b/java/org/apache/catalina/loader/WebappClassLoader.java
index d9de6b4..e5ec41c 100644
--- a/java/org/apache/catalina/loader/WebappClassLoader.java
+++ b/java/org/apache/catalina/loader/WebappClassLoader.java
@@ -116,7 +116,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Craig R. McClanahan
- * @version $Id: WebappClassLoader.java 1162172 2011-08-26 17:12:33Z markt $
+ * @version $Id: WebappClassLoader.java 1163802 2011-08-31 20:35:22Z slaurent $
  */
 public class WebappClassLoader
     extends URLClassLoader
@@ -2898,11 +2898,22 @@ public class WebappClassLoader
 
                 // Note : Not getting an exception here means the resource was
                 // found
-                entry = findResourceInternal(files[i], path);
 
                 ResourceAttributes attributes =
                     (ResourceAttributes) resources.getAttributes(fullPath);
                 contentLength = (int) attributes.getContentLength();
+                String canonicalPath = attributes.getCanonicalPath();
+                if (canonicalPath != null) {
+                    // we create the ResourceEntry based on the information returned
+                    // by the DirContext rather than just using the path to the
+                    // repository. This allows to have smart DirContext implementations 
+                    // that "virtualize" the docbase (e.g. Eclipse WTP)
+                    entry = findResourceInternal(new File(canonicalPath), "");
+                } else {
+                    // probably a resource not in the filesystem (e.g. in a
+                    // packaged war)
+                    entry = findResourceInternal(files[i], path);
+                }
                 entry.lastModified = attributes.getLastModified();
 
                 if (resource != null) {
diff --git a/java/org/apache/catalina/loader/WebappLoader.java b/java/org/apache/catalina/loader/WebappLoader.java
index 891700d..3c11f0f 100644
--- a/java/org/apache/catalina/loader/WebappLoader.java
+++ b/java/org/apache/catalina/loader/WebappLoader.java
@@ -77,7 +77,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: WebappLoader.java 1162172 2011-08-26 17:12:33Z markt $
+ * @version $Id: WebappLoader.java 1174921 2011-09-23 17:51:56Z kkolinko $
  */
 
 public class WebappLoader extends LifecycleMBeanBase
@@ -1036,7 +1036,6 @@ public class WebappLoader extends LifecycleMBeanBase
 
         // Assemble the class path information from our class loader chain
         ClassLoader loader = getClassLoader();
-        int layers = 0;
         int n = 0;
         while (loader != null) {
             if (!(loader instanceof URLClassLoader)) {
@@ -1073,7 +1072,6 @@ public class WebappLoader extends LifecycleMBeanBase
                 n++;
             }
             loader = loader.getParent();
-            layers++;
         }
 
         this.classpath=classpath.toString();
diff --git a/java/org/apache/catalina/security/SecurityClassLoad.java b/java/org/apache/catalina/security/SecurityClassLoad.java
index 28d64e2..549a1e8 100644
--- a/java/org/apache/catalina/security/SecurityClassLoad.java
+++ b/java/org/apache/catalina/security/SecurityClassLoad.java
@@ -25,7 +25,7 @@ package org.apache.catalina.security;
  *
  * @author Glenn L. Nielsen
  * @author Jean-Francois Arcand
- * @version $Id: SecurityClassLoad.java 1144031 2011-07-07 20:53:51Z markt $
+ * @version $Id: SecurityClassLoad.java 1174064 2011-09-22 11:23:57Z markt $
  */
 
 public final class SecurityClassLoad {
@@ -87,10 +87,10 @@ public final class SecurityClassLoad {
              "DefaultInstanceManager$3");
         loader.loadClass
             (basePackage +
-             "DefaultInstanceManager$4");
+             "DefaultInstanceManager$AnnotationCacheEntry");
         loader.loadClass
             (basePackage +
-             "DefaultInstanceManager$5");
+             "DefaultInstanceManager$AnnotationCacheEntryType");
         loader.loadClass
             (basePackage +
              "ApplicationHttpRequest$AttributeNamesEnumerator");
diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java b/java/org/apache/catalina/servlets/DefaultServlet.java
index 9ab8558..96be826 100644
--- a/java/org/apache/catalina/servlets/DefaultServlet.java
+++ b/java/org/apache/catalina/servlets/DefaultServlet.java
@@ -114,7 +114,7 @@ import org.apache.tomcat.util.res.StringManager;
  * </p>
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: DefaultServlet.java 1145380 2011-07-11 22:08:06Z markt $
+ * @version $Id: DefaultServlet.java 1174914 2011-09-23 17:47:08Z kkolinko $
  */
 
 public class DefaultServlet
@@ -1379,13 +1379,6 @@ public class DefaultServlet
 
         String name = cacheEntry.name;
 
-        // Number of characters to trim from the beginnings of filenames
-        int trim = name.length();
-        if (!name.endsWith("/"))
-            trim += 1;
-        if (name.equals("/"))
-            trim = 1;
-
         // Prepare a writer to a buffered area
         ByteArrayOutputStream stream = new ByteArrayOutputStream();
         OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8");
diff --git a/java/org/apache/catalina/session/ManagerBase.java b/java/org/apache/catalina/session/ManagerBase.java
index 6656303..99fbf93 100644
--- a/java/org/apache/catalina/session/ManagerBase.java
+++ b/java/org/apache/catalina/session/ManagerBase.java
@@ -55,7 +55,7 @@ import org.apache.tomcat.util.res.StringManager;
  * be subclassed to create more sophisticated Manager implementations.
  *
  * @author Craig R. McClanahan
- * @version $Id: ManagerBase.java 1097899 2011-04-29 17:49:37Z markt $
+ * @version $Id: ManagerBase.java 1175277 2011-09-24 22:37:12Z kkolinko $
  */
 
 public abstract class ManagerBase extends LifecycleMBeanBase
@@ -86,6 +86,12 @@ public abstract class ManagerBase extends LifecycleMBeanBase
 
 
     /**
+     * The descriptive name of this Manager implementation (for logging).
+     */
+    private static final String name = "ManagerBase";
+
+
+    /**
      * The default maximum inactive interval for Sessions created by
      * this Manager.
      */
@@ -99,12 +105,6 @@ public abstract class ManagerBase extends LifecycleMBeanBase
 
 
     /**
-     * The descriptive name of this Manager implementation (for logging).
-     */
-    protected static String name = "ManagerBase";
-
-
-    /**
      * The Java class name of the secure random number generator class to be
      * used when generating session identifiers. The random number generator
      * class must be self-seeding and have a zero-argument constructor. If not
diff --git a/java/org/apache/catalina/session/StandardSession.java b/java/org/apache/catalina/session/StandardSession.java
index c5b4388..3b5935b 100644
--- a/java/org/apache/catalina/session/StandardSession.java
+++ b/java/org/apache/catalina/session/StandardSession.java
@@ -77,7 +77,7 @@ import org.apache.tomcat.util.res.StringManager;
  * @author Craig R. McClanahan
  * @author Sean Legassick
  * @author <a href="mailto:jon at latchkey.com">Jon S. Stevens</a>
- * @version $Id: StandardSession.java 1094069 2011-04-16 22:25:28Z markt $
+ * @version $Id: StandardSession.java 1172259 2011-09-18 11:44:45Z rjung $
  */
 
 public class StandardSession implements HttpSession, Session, Serializable {
@@ -1449,7 +1449,7 @@ public class StandardSession implements HttpSession, Session, Serializable {
             throw new IllegalStateException(sm.getString(
                     "standardSession.setAttribute.ise", getIdInternal()));
         if ((manager != null) && manager.getDistributable() &&
-          !(value instanceof Serializable))
+          !isAttributeDistributable(name, value))
             throw new IllegalArgumentException
                 (sm.getString("standardSession.setAttribute.iae", name));
         // Construct an event with the new value
@@ -1558,6 +1558,19 @@ public class StandardSession implements HttpSession, Session, Serializable {
         return (this.isValid || this.expiring);
     }
 
+    /**
+     * Check whether the Object can be distributed. This implementation
+     * simply checks for serializability. Derived classes might use other
+     * distribution technology not based on serialization and can extend
+     * this check.
+     * @param name The name of the attribute to check
+     * @param value The value of the attribute to check
+     * @return true if the attribute is distributable, false otherwise
+     */
+    protected boolean isAttributeDistributable(String name, Object value) {
+        return value instanceof Serializable;
+    }
+
 
     /**
      * Read a serialized version of this session object from the specified
@@ -1694,7 +1707,7 @@ public class StandardSession implements HttpSession, Session, Serializable {
 
 
     /**
-     * Exclude attribute that cannot be serialized.
+     * Exclude standard attributes that cannot be serialized.
      * @param name the attribute's name
      */
     protected boolean exclude(String name){
diff --git a/java/org/apache/catalina/startup/Embedded.java b/java/org/apache/catalina/startup/Embedded.java
index 2d96973..34d6001 100644
--- a/java/org/apache/catalina/startup/Embedded.java
+++ b/java/org/apache/catalina/startup/Embedded.java
@@ -98,7 +98,7 @@ import org.apache.tomcat.util.res.StringManager;
  * of how Tomcat is set up and launched as an Embedded application.
  *
  * @author Craig R. McClanahan
- * @version $Id: Embedded.java 1134042 2011-06-09 19:04:37Z markt $
+ * @version $Id: Embedded.java 1175897 2011-09-26 15:01:21Z markt $
  * 
  * @deprecated Use {@link Tomcat} instead.
  */
@@ -160,7 +160,7 @@ public class Embedded  extends StandardService {
     /**
      * Custom mappings of login methods to authenticators
      */
-    protected HashMap<String,Authenticator> authenticators;
+    protected volatile HashMap<String,Authenticator> authenticators;
 
 
     /**
diff --git a/java/org/apache/catalina/startup/ExpandWar.java b/java/org/apache/catalina/startup/ExpandWar.java
index eb9504e..5175004 100644
--- a/java/org/apache/catalina/startup/ExpandWar.java
+++ b/java/org/apache/catalina/startup/ExpandWar.java
@@ -30,6 +30,7 @@ import java.nio.channels.FileChannel;
 import java.util.Enumeration;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.zip.ZipException;
 
 import org.apache.catalina.Globals;
 import org.apache.catalina.Host;
@@ -44,7 +45,7 @@ import org.apache.tomcat.util.res.StringManager;
  * @author Craig R. McClanahan
  * @author Remy Maucherat
  * @author Glenn L. Nielsen
- * @version $Revision: 1162172 $
+ * @version $Revision: 1173343 $
  */
 
 public class ExpandWar {
@@ -137,6 +138,9 @@ public class ExpandWar {
                 }
                 input = jarFile.getInputStream(jarEntry);
 
+                if(null == input)
+                    throw new ZipException(sm.getString("expandWar.missingJarEntry", jarEntry.getName()));
+
                 // Bugzilla 33636
                 expand(input, expandedFile);
                 long lastModified = jarEntry.getTime();
diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties
index b1f0e8a..2208705 100644
--- a/java/org/apache/catalina/startup/LocalStrings.properties
+++ b/java/org/apache/catalina/startup/LocalStrings.properties
@@ -73,6 +73,7 @@ expandWar.copy=Error copying {0} to {1}
 expandWar.createFailed=Unable to create the directory [{0}]
 expandWar.deleteFailed=[{0}] could not be completely deleted. The presence of the remaining files may cause problems
 expandWar.illegalPath=The archive [{0}] is malformed and will be ignored: an entry contains an illegal path [{1}] which was not expanded to [{2}] since that is outside of the defined docBase [{3}]
+expandWar.missingJarEntry=Cannot get input stream for JarEntry "{0}" - broken WAR file?
 hostConfig.appBase=Application base [{1}] for host [{0}] does not exist or is not a directory. deployOnStartUp and autoDeploy have been set to false to prevent deployment errors. Other errors may still occur.
 hostConfig.canonicalizing=Error delete redeploy resources from context [{0}]
 hostConfig.cce=Lifecycle event data object {0} is not a Host
diff --git a/java/org/apache/catalina/valves/SSLValve.java b/java/org/apache/catalina/valves/SSLValve.java
index 4ef7d31..84d8cc5 100644
--- a/java/org/apache/catalina/valves/SSLValve.java
+++ b/java/org/apache/catalina/valves/SSLValve.java
@@ -125,6 +125,7 @@ public class SSLValve extends ValveBase {
         strcert0 = mygetHeader(request, "ssl_session_id");
         if (strcert0 != null) {
             request.setAttribute(Globals.SSL_SESSION_ID_ATTR, strcert0);
+            request.setAttribute(Globals.SSL_SESSION_ID_TOMCAT_ATTR, strcert0);
         }
         strcert0 = mygetHeader(request, "ssl_cipher_usekeysize");
         if (strcert0 != null) {
diff --git a/java/org/apache/catalina/valves/StuckThreadDetectionValve.java b/java/org/apache/catalina/valves/StuckThreadDetectionValve.java
index 911da42..b0c64ea 100644
--- a/java/org/apache/catalina/valves/StuckThreadDetectionValve.java
+++ b/java/org/apache/catalina/valves/StuckThreadDetectionValve.java
@@ -177,7 +177,7 @@ public class StuckThreadDetectionValve extends ValveBase {
         // Keeping a reference to the thread object here does not prevent
         // GC'ing, as the reference is removed from the Map in the finally clause
 
-        Long key = new Long(Thread.currentThread().getId());
+        Long key = Long.valueOf(Thread.currentThread().getId());
         StringBuffer requestUrl = request.getRequestURL();
         if(request.getQueryString()!=null) {
             requestUrl.append("?");
@@ -240,7 +240,7 @@ public class StuckThreadDetectionValve extends ValveBase {
         return result;
     }
 
-    private class MonitoredThread {
+    private static class MonitoredThread {
 
         /**
          * Reference to the thread to get a stack trace from background task
@@ -288,7 +288,7 @@ public class StuckThreadDetectionValve extends ValveBase {
         }
     }
 
-    private class CompletedStuckThread {
+    private static class CompletedStuckThread {
 
         private String threadName;
         private long totalActiveTime;
diff --git a/java/org/apache/coyote/AsyncStateMachine.java b/java/org/apache/coyote/AsyncStateMachine.java
index 1160f4a..00af3a3 100644
--- a/java/org/apache/coyote/AsyncStateMachine.java
+++ b/java/org/apache/coyote/AsyncStateMachine.java
@@ -325,7 +325,7 @@ public class AsyncStateMachine {
     }
     
     
-    public void recycle() {
+    public synchronized void recycle() {
         asyncCtxt = null;
         state = AsyncState.DISPATCHED;
     }
diff --git a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
index fceefdd..056c6ca 100644
--- a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
+++ b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
@@ -759,7 +759,6 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> {
                     secret = true;
                     if (!tmpMB.equals(requiredSecret)) {
                         response.setStatus(403);
-                        adapter.log(request, response, 0);
                         error = true;
                     }
                 }
@@ -776,7 +775,6 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> {
         // Check if secret was submitted if required
         if ((requiredSecret != null) && !secret) {
             response.setStatus(403);
-            adapter.log(request, response, 0);
             error = true;
         }
 
@@ -810,6 +808,9 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> {
         MessageBytes valueMB = request.getMimeHeaders().getValue("host");
         parseHost(valueMB);
 
+        if (error) {
+            adapter.log(request, response, 0);
+        }
     }
 
 
@@ -825,7 +826,6 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> {
                 request.serverName().duplicate(request.localName());
             } catch (IOException e) {
                 response.setStatus(400);
-                adapter.log(request, response, 0);
                 error = true;
             }
             return;
@@ -877,7 +877,6 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> {
                     error = true;
                     // 400 - Bad request
                     response.setStatus(400);
-                    adapter.log(request, response, 0);
                     break;
                 }
                 port = port + (charValue * mult);
diff --git a/java/org/apache/coyote/ajp/AjpAprProcessor.java b/java/org/apache/coyote/ajp/AjpAprProcessor.java
index d6b0b56..eca67e1 100644
--- a/java/org/apache/coyote/ajp/AjpAprProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpAprProcessor.java
@@ -113,6 +113,7 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
         long socketRef = socket.getSocket().longValue();
         Socket.setrbb(socketRef, inputBuffer);
         Socket.setsbb(socketRef, outputBuffer);
+        boolean cping = false;
 
         // Error flag
         error = false;
@@ -120,7 +121,6 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
         boolean keptAlive = false;
 
         while (!error && !endpoint.isPaused()) {
-
             // Parsing the request header
             try {
                 // Get first message of the request
@@ -134,6 +134,11 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
                 // not regular request processing
                 int type = requestHeaderMessage.getByte();
                 if (type == Constants.JK_AJP13_CPING_REQUEST) {
+                    if (endpoint.isPaused()) {
+                        recycle(true);
+                        break;
+                    }
+                    cping = true;
                     if (Socket.send(socketRef, pongMessageArray, 0,
                             pongMessageArray.length) < 0) {
                         error = true;
@@ -148,7 +153,6 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
                     error = true;
                     break;
                 }
-
                 keptAlive = true;
                 request.setStartTime(System.currentTimeMillis());
             } catch (IOException e) {
@@ -178,6 +182,14 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
                 }
             }
 
+            if (!error && !cping && endpoint.isPaused()) {
+                // 503 - Service unavailable
+                response.setStatus(503);
+                adapter.log(request, response, 0);
+                error = true;
+            }
+            cping = false;
+
             // Process the request in the adapter
             if (!error) {
                 try {
@@ -221,13 +233,15 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
         }
 
         rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
-        
-        if (error || endpoint.isPaused()) {
-            return SocketState.CLOSED;
-        } else if (isAsync()) {
-            return SocketState.LONG;
+
+        if (!error && !endpoint.isPaused()) {
+            if (isAsync()) {
+                return SocketState.LONG;
+            } else {
+                return SocketState.OPEN;
+            }
         } else {
-            return SocketState.OPEN;
+            return SocketState.CLOSED;
         }
     }
 
@@ -250,7 +264,7 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
                         SocketStatus.OPEN);
             }
         } else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) {
-            if (param==null) return;
+            if (param == null) return;
             long timeout = ((Long)param).longValue();
             socket.setTimeout(timeout);
         } else if (actionCode == ActionCode.ASYNC_DISPATCH) {
@@ -259,8 +273,6 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
                         SocketStatus.OPEN);
             }
         }
-
-
     }
 
 
diff --git a/java/org/apache/coyote/ajp/AjpAprProtocol.java b/java/org/apache/coyote/ajp/AjpAprProtocol.java
index d314cb2..aa873d8 100644
--- a/java/org/apache/coyote/ajp/AjpAprProtocol.java
+++ b/java/org/apache/coyote/ajp/AjpAprProtocol.java
@@ -126,7 +126,7 @@ public class AjpAprProtocol extends AbstractAjpProtocol {
             recycledProcessors.offer(processor);
             if (addToPoller) {
                 ((AprEndpoint)proto.endpoint).getPoller().add(
-                        socket.getSocket().longValue());
+                        socket.getSocket().longValue(), true);
             }
         }
 
diff --git a/java/org/apache/coyote/ajp/AjpNioProcessor.java b/java/org/apache/coyote/ajp/AjpNioProcessor.java
index bd53f13..29f5135 100644
--- a/java/org/apache/coyote/ajp/AjpNioProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpNioProcessor.java
@@ -98,6 +98,7 @@ public class AjpNioProcessor extends AbstractAjpProcessor<NioChannel> {
         this.socket = socket.getSocket();
         
         long soTimeout = endpoint.getSoTimeout();
+        boolean cping = false;
 
         // Error flag
         error = false;
@@ -118,6 +119,11 @@ public class AjpNioProcessor extends AbstractAjpProcessor<NioChannel> {
                 // not regular request processing
                 int type = requestHeaderMessage.getByte();
                 if (type == Constants.JK_AJP13_CPING_REQUEST) {
+                    if (endpoint.isPaused()) {
+                        recycle(true);
+                        break;
+                    }
+                    cping = true;
                     try {
                         output(pongMessageArray, 0, pongMessageArray.length);
                     } catch (IOException e) {
@@ -163,12 +169,13 @@ public class AjpNioProcessor extends AbstractAjpProcessor<NioChannel> {
                 }
             }
 
-            if (endpoint.isPaused()) {
+            if (!error && !cping && endpoint.isPaused()) {
                 // 503 - Service unavailable
                 response.setStatus(503);
                 adapter.log(request, response, 0);
                 error = true;
             }
+            cping = false;
 
             // Process the request in the adapter
             if (!error) {
@@ -186,7 +193,7 @@ public class AjpNioProcessor extends AbstractAjpProcessor<NioChannel> {
                     error = true;
                 }
             }
-            
+
             if (isAsync() && !error) {
                 break;
             }
@@ -216,7 +223,7 @@ public class AjpNioProcessor extends AbstractAjpProcessor<NioChannel> {
 
             recycle(false);
         }
-        
+
         rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
 
         if (!error && !endpoint.isPaused()) {
@@ -228,10 +235,9 @@ public class AjpNioProcessor extends AbstractAjpProcessor<NioChannel> {
         } else {
             return SocketState.CLOSED;
         }
-        
     }
 
-    
+
     // ----------------------------------------------------- ActionHook Methods
 
 
diff --git a/java/org/apache/coyote/ajp/AjpProcessor.java b/java/org/apache/coyote/ajp/AjpProcessor.java
index cdebea6..5998989 100644
--- a/java/org/apache/coyote/ajp/AjpProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpProcessor.java
@@ -111,6 +111,7 @@ public class AjpProcessor extends AbstractAjpProcessor<Socket> {
         if (keepAliveTimeout > 0) {
             soTimeout = socket.getSocket().getSoTimeout();
         }
+        boolean cping = false;
 
         // Error flag
         error = false;
@@ -136,6 +137,11 @@ public class AjpProcessor extends AbstractAjpProcessor<Socket> {
                 // not regular request processing
                 int type = requestHeaderMessage.getByte();
                 if (type == Constants.JK_AJP13_CPING_REQUEST) {
+                    if (endpoint.isPaused()) {
+                        recycle(true);
+                        break;
+                    }
+                    cping = true;
                     try {
                         output.write(pongMessageArray);
                     } catch (IOException e) {
@@ -179,12 +185,13 @@ public class AjpProcessor extends AbstractAjpProcessor<Socket> {
                 }
             }
 
-            if (endpoint.isPaused()) {
+            if (!error && !cping && endpoint.isPaused()) {
                 // 503 - Service unavailable
                 response.setStatus(503);
                 adapter.log(request, response, 0);
                 error = true;
             }
+            cping = false;
 
             // Process the request in the adapter
             if (!error) {
diff --git a/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java b/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java
index 2f79756..8cf49f6 100644
--- a/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java
+++ b/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java
@@ -103,10 +103,10 @@ public abstract class AbstractHttp11JsseProtocol
         return endpoint.getAllowUnsafeLegacyRenegotiation();
     }
 
-    private String sslImplemenationName = null;
-    public String getSslImplemenationName() { return sslImplemenationName; }
-    public void setSslImplemenationName(String s) {
-        this.sslImplemenationName = s;
+    private String sslImplementationName = null;
+    public String getSslImplementationName() { return sslImplementationName; }
+    public void setSslImplementationName(String s) {
+        this.sslImplementationName = s;
     }
 
     // ------------------------------------------------------- Lifecycle methods
@@ -115,7 +115,7 @@ public abstract class AbstractHttp11JsseProtocol
     public void init() throws Exception {
         // SSL implementation needs to be in place before end point is
         // initialized
-        sslImplementation = SSLImplementation.getInstance(sslImplemenationName);
+        sslImplementation = SSLImplementation.getInstance(sslImplementationName);
         super.init();
     }
 }
diff --git a/java/org/apache/coyote/http11/AbstractHttp11Processor.java b/java/org/apache/coyote/http11/AbstractHttp11Processor.java
index 0baadc0..0e46c06 100644
--- a/java/org/apache/coyote/http11/AbstractHttp11Processor.java
+++ b/java/org/apache/coyote/http11/AbstractHttp11Processor.java
@@ -47,6 +47,7 @@ import org.apache.tomcat.util.http.MimeHeaders;
 import org.apache.tomcat.util.net.AbstractEndpoint;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
 import org.apache.tomcat.util.net.SocketStatus;
+import org.apache.tomcat.util.net.SocketWrapper;
 import org.apache.tomcat.util.res.StringManager;
 
 public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
@@ -79,6 +80,36 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
 
 
     /**
+     * Flag used to indicate that the socket should be kept open (e.g. for keep
+     * alive or send file.
+     */
+    protected boolean openSocket = false;
+
+
+    /**
+     * Flag used to indicate that the socket should treat the next request
+     * processed like a keep-alive connection - i.e. one where there may not be
+     * any data to process. The initial value of this flag on entering the
+     * process method is different for connectors that use polling (NIO / APR -
+     * data is always expected) compared to those that use blocking (BIO - data
+     * is only expected if the connection isn't in the keep-alive state).
+     */
+    protected boolean keptAlive;
+
+
+    /**
+     * Flag that indicates that send file processing is in progress and that the
+     * socket should not be returned to the poller (where a poller is used).
+     */
+    protected boolean sendfileInProgress = false;
+
+
+    /**
+     * Flag that indicates if the request headers have been completely read.
+     */
+    protected boolean readComplete = true;
+
+    /**
      * HTTP/1.1 flag.
      */
     protected boolean http11 = true;
@@ -607,6 +638,12 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                status == 501 /* SC_NOT_IMPLEMENTED */;
     }
 
+    
+    /**
+     * Allows the super class to set the socket wrapper being used.
+     */
+    protected abstract void setSocketWrapper(SocketWrapper<S> socketWrapper);
+
 
     /**
      * Exposes input buffer to super class to allow better code re-use.
@@ -747,6 +784,7 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
             InputFilter savedBody = new SavedRequestInputFilter(body);
             savedBody.setRequest(request);
 
+            @SuppressWarnings("unchecked")
             AbstractInputBuffer<S> internalBuffer = (AbstractInputBuffer<S>)
                 request.getInputBuffer();
             internalBuffer.addActiveFilter(savedBody);
@@ -786,6 +824,231 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
 
 
     /**
+     * Configures the timeout to be used for reading the request line.
+     */
+    protected abstract void setRequestLineReadTimeout() throws IOException;
+
+
+    /**
+     * Defines how a connector handles an incomplete request line read.
+     * 
+     * @return <code>true</code> if the processor should break out of the
+     *         processing loop, otherwise <code>false</code>.
+     */
+    protected abstract boolean handleIncompleteRequestLineRead();
+
+
+    /**
+     * Set the socket timeout.
+     */
+    protected abstract void setSocketTimeout(int timeout) throws IOException;
+
+
+    /**
+     * Process pipelined HTTP requests using the specified input and output
+     * streams.
+     *
+     * @param socketWrapper Socket from which the HTTP requests will be read
+     *               and the HTTP responses will be written.
+     *  
+     * @throws IOException error during an I/O operation
+     */
+    @Override
+    public SocketState process(SocketWrapper<S> socketWrapper)
+        throws IOException {
+        RequestInfo rp = request.getRequestProcessor();
+        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
+
+        // Setting up the I/O
+        setSocketWrapper(socketWrapper);
+        getInputBuffer().init(socketWrapper, endpoint);
+        getOutputBuffer().init(socketWrapper, endpoint);
+
+        // Flags
+        error = false;
+        keepAlive = true;
+        comet = false;
+        openSocket = false;
+        sendfileInProgress = false;
+        readComplete = true;
+        if (endpoint.getUsePolling()) {
+            keptAlive = false;
+        } else {
+            keptAlive = socketWrapper.isKeptAlive();
+        }
+
+        if (disableKeepAlive()) {
+            socketWrapper.setKeepAliveLeft(0);
+        }
+
+        while (!error && keepAlive && !comet && !isAsync() &&
+                !endpoint.isPaused()) {
+
+            // Parsing the request header
+            try {
+                setRequestLineReadTimeout();
+                
+                if (!getInputBuffer().parseRequestLine(keptAlive)) {
+                    if (handleIncompleteRequestLineRead()) {
+                        break;
+                    }
+                }
+
+                if (endpoint.isPaused()) {
+                    // 503 - Service unavailable
+                    response.setStatus(503);
+                    error = true;
+                } else {
+                    request.setStartTime(System.currentTimeMillis());
+                    keptAlive = true;
+                    // Currently only NIO will ever return false here
+                    if (!getInputBuffer().parseHeaders()) {
+                        // We've read part of the request, don't recycle it
+                        // instead associate it with the socket
+                        openSocket = true;
+                        readComplete = false;
+                        break;
+                    }
+                    if (!disableUploadTimeout) {
+                        setSocketTimeout(connectionUploadTimeout);
+                    }
+                }
+            } catch (IOException e) {
+                if (getLog().isDebugEnabled()) {
+                    getLog().debug(
+                            sm.getString("http11processor.header.parse"), e);
+                }
+                error = true;
+                break;
+            } catch (Throwable t) {
+                ExceptionUtils.handleThrowable(t);
+                if (getLog().isDebugEnabled()) {
+                    getLog().debug(
+                            sm.getString("http11processor.header.parse"), t);
+                }
+                // 400 - Bad Request
+                response.setStatus(400);
+                adapter.log(request, response, 0);
+                error = true;
+            }
+
+            if (!error) {
+                // Setting up filters, and parse some request headers
+                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
+                try {
+                    prepareRequest();
+                } catch (Throwable t) {
+                    ExceptionUtils.handleThrowable(t);
+                    if (getLog().isDebugEnabled()) {
+                        getLog().debug(sm.getString(
+                                "http11processor.request.prepare"), t);
+                    }
+                    // 400 - Internal Server Error
+                    response.setStatus(400);
+                    adapter.log(request, response, 0);
+                    error = true;
+                }
+            }
+
+            if (maxKeepAliveRequests == 1) {
+                keepAlive = false;
+            } else if (maxKeepAliveRequests > 0 &&
+                    socketWrapper.decrementKeepAlive() <= 0) {
+                keepAlive = false;
+            }
+
+            // Process the request in the adapter
+            if (!error) {
+                try {
+                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
+                    adapter.service(request, response);
+                    // Handle when the response was committed before a serious
+                    // error occurred.  Throwing a ServletException should both
+                    // set the status to 500 and set the errorException.
+                    // If we fail here, then the response is likely already
+                    // committed, so we can't try and set headers.
+                    if(keepAlive && !error) { // Avoid checking twice.
+                        error = response.getErrorException() != null ||
+                                (!isAsync() &&
+                                statusDropsConnection(response.getStatus()));
+                    }
+                    setCometTimeouts(socketWrapper);
+                } catch (InterruptedIOException e) {
+                    error = true;
+                } catch (Throwable t) {
+                    ExceptionUtils.handleThrowable(t);
+                    getLog().error(sm.getString(
+                            "http11processor.request.process"), t);
+                    // 500 - Internal Server Error
+                    response.setStatus(500);
+                    adapter.log(request, response, 0);
+                    error = true;
+                }
+            }
+
+            // Finish the handling of the request
+            rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
+
+            if (!isAsync() && !comet) {
+                if (error) {
+                    // If we know we are closing the connection, don't drain
+                    // input. This way uploading a 100GB file doesn't tie up the
+                    // thread if the servlet has rejected it.
+                    getInputBuffer().setSwallowInput(false);
+                }
+                endRequest();
+            }
+
+            rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
+
+            // If there was an error, make sure the request is counted as
+            // and error, and update the statistics counter
+            if (error) {
+                response.setStatus(500);
+            }
+            request.updateCounters();
+
+            if (!isAsync() && !comet || error) {
+                getInputBuffer().nextRequest();
+                getOutputBuffer().nextRequest();
+            }
+
+            if (!disableUploadTimeout) {
+                setSocketTimeout(endpoint.getSoTimeout());
+            }
+
+            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
+
+            if (breakKeepAliveLoop(socketWrapper)) {
+                break;
+            }
+        }
+
+        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
+
+        if (error || endpoint.isPaused()) {
+            return SocketState.CLOSED;
+        } else if (isAsync() || comet) {
+            return SocketState.LONG;
+        } else {
+            if (sendfileInProgress) {
+                return SocketState.SENDFILE;
+            } else {
+                if (openSocket) {
+                    if (readComplete) {
+                        return SocketState.OPEN;
+                    } else {
+                        return SocketState.LONG;
+                    }
+                } else {
+                    return SocketState.CLOSED;
+                }
+            }
+        }
+    }
+
+
+    /**
      * After reading the request headers, we have to setup the request filters.
      */
     protected void prepareRequest() {
@@ -823,7 +1086,6 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                           " Unsupported HTTP version \""+protocolMB+"\"");
             }
             response.setStatus(505);
-            adapter.log(request, response, 0);
         }
 
         MessageBytes methodMB = request.method();
@@ -919,7 +1181,6 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                     error = true;
                     // 501 - Unimplemented
                     response.setStatus(501);
-                    adapter.log(request, response, 0);
                 }
                 startPos = commaPos + 1;
                 commaPos = transferEncodingValue.indexOf(',', startPos);
@@ -935,7 +1196,6 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                               " Unsupported transfer encoding \""+encodingName+"\"");
                 }
                 response.setStatus(501);
-                adapter.log(request, response, 0);
             }
         }
 
@@ -958,7 +1218,6 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                           " host header missing");
             }
             response.setStatus(400);
-            adapter.log(request, response, 0);
         }
 
         parseHost(valueMB);
@@ -988,6 +1247,10 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
             request.setAttribute("org.apache.tomcat.comet.timeout.support",
                     Boolean.TRUE);
         }
+        
+        if (error) {
+            adapter.log(request, response, 0);
+        }
     }
 
 
@@ -1207,7 +1470,6 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                     error = true;
                     // 400 - Bad request
                     response.setStatus(400);
-                    adapter.log(request, response, 0);
                     break;
                 }
                 port = port + (charValue * mult);
@@ -1271,6 +1533,12 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
     protected abstract void resetTimeouts();
 
 
+    /**
+     * Provides a mechanism for those connectors (currently only NIO) that need
+     * that need to set comet timeouts.
+     */
+    protected abstract void setCometTimeouts(SocketWrapper<S> socketWrapper);
+
     public void endRequest() {
 
         // Finish the handling of the request
@@ -1282,8 +1550,9 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
             ExceptionUtils.handleThrowable(t);
             getLog().error(sm.getString("http11processor.request.finish"), t);
             // 500 - Internal Server Error
+            // Can't add a 500 to the access log since that has already been
+            // written in the Adapter.service method.
             response.setStatus(500);
-            adapter.log(request, response, 0);
             error = true;
         }
         try {
@@ -1297,7 +1566,18 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
         }
 
     }
-    
+
+
+    /**
+     * Checks to see if the keep-alive loop should be broken, performing any
+     * processing (e.g. sendfile handling) that may have an impact on whether
+     * or not the keep-alive loop should be broken.
+     * @return true if the keep-alive loop should be broken
+     */
+    protected abstract boolean breakKeepAliveLoop(
+            SocketWrapper<S> socketWrapper);
+
+
     public final void recycle() {
         getInputBuffer().recycle();
         getOutputBuffer().recycle();
diff --git a/java/org/apache/coyote/http11/Http11AprProcessor.java b/java/org/apache/coyote/http11/Http11AprProcessor.java
index 3b19181..9918980 100644
--- a/java/org/apache/coyote/http11/Http11AprProcessor.java
+++ b/java/org/apache/coyote/http11/Http11AprProcessor.java
@@ -157,207 +157,91 @@ public class Http11AprProcessor extends AbstractHttp11Processor<Long> {
         }
     }
     
-    /**
-     * Process pipelined HTTP requests using the specified input and output
-     * streams.
-     *
-     * @param socketWrapper Socket from which the HTTP requests will be read
-     *               and the HTTP responses will be written.
-     *  
-     * @throws IOException error during an I/O operation
-     */
     @Override
-    public SocketState process(SocketWrapper<Long> socketWrapper)
-        throws IOException {
-        RequestInfo rp = request.getRequestProcessor();
-        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
+    protected boolean disableKeepAlive() {
+        return false;
+    }
 
-        // Setting up the socket
-        this.socket = socketWrapper;
-        inputBuffer.init(socketWrapper, endpoint);
-        outputBuffer.init(socketWrapper, endpoint);
 
-        // Error flag
-        error = false;
-        keepAlive = true;
-        comet = false;
+    @Override
+    protected void setRequestLineReadTimeout() throws IOException {
+        // Timeouts while in the poller are handled entirely by the poller
+        // Only need to be concerned with socket timeouts
+
+        // APR uses simulated blocking so if some request line data is present
+        // then it must all be presented (with the normal socket timeout).
+        
+        // When entering the processing loop for the first time there will
+        // always be some data to read so the keep-alive timeout is not required
+        
+        // For the second and subsequent executions of the processing loop, if
+        // there is no request line data present then no further data will be
+        // read from the socket. If there is request line data present then it
+        // must all be presented (with the normal socket timeout)
+
+        // When the socket is created it is given the correct timeout.
+        // sendfile may change the timeout but will restore it
+        // This processor may change the timeout for uploads but will restore it
+        
+        // NO-OP
+    }
 
-        int soTimeout = endpoint.getSoTimeout();
 
-        if (disableKeepAlive()) {
-            socketWrapper.setKeepAliveLeft(0);
+    @Override
+    protected boolean handleIncompleteRequestLineRead() {
+        // This means that no data is available right now
+        // (long keepalive), so that the processor should be recycled
+        // and the method should return true
+        openSocket = true;
+        if (endpoint.isPaused()) {
+            // 503 - Service unavailable
+            response.setStatus(503);
+            adapter.log(request, response, 0);
+            error = true;
+        } else {
+            return true;
         }
+        return false;
+    }
 
-        boolean keptAlive = false;
-        boolean openSocket = false;
-        boolean sendfileInProgress = false;
 
-        long socketRef = socketWrapper.getSocket().longValue();
+    @Override
+    protected void setSocketTimeout(int timeout) {
+        Socket.timeoutSet(socket.getSocket().longValue(), timeout * 1000);
+    }
+    
+    
+    @Override
+    protected void setCometTimeouts(SocketWrapper<Long> socketWrapper) {
+        // NO-OP for APR/native
+    }
 
-        while (!error && keepAlive && !comet && !isAsync() && !endpoint.isPaused()) {
 
-            // Parsing the request header
-            try {
-                if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) {
-                    Socket.timeoutSet(socketRef, soTimeout * 1000);
-                }
-                if (!inputBuffer.parseRequestLine(keptAlive)) {
-                    // This means that no data is available right now
-                    // (long keepalive), so that the processor should be recycled
-                    // and the method should return true
-                    openSocket = true;
-                    if (endpoint.isPaused()) {
-                        // 503 - Service unavailable
-                        response.setStatus(503);
-                        adapter.log(request, response, 0);
-                        error = true;
-                    } else {
-                        break;
-                    }
-                }
-                if (!endpoint.isPaused()) {
-                    request.setStartTime(System.currentTimeMillis());
-                    keptAlive = true;
-                    if (!disableUploadTimeout) {
-                        Socket.timeoutSet(socketRef,
-                                connectionUploadTimeout * 1000);
-                    }
-                    inputBuffer.parseHeaders();
-                }
-            } catch (IOException e) {
-                error = true;
-                break;
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("http11processor.header.parse"), t);
-                }
-                // 400 - Bad Request
-                response.setStatus(400);
-                adapter.log(request, response, 0);
-                error = true;
-            }
-
-            if (!error) {
-                // Setting up filters, and parse some request headers
-                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
-                try {
-                    prepareRequest();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
+    @Override
+    protected boolean breakKeepAliveLoop(SocketWrapper<Long> socketWrapper) {
+        openSocket = keepAlive;
+        // Do sendfile as needed: add socket to sendfile and end
+        if (sendfileData != null && !error) {
+            sendfileData.socket = socketWrapper.getSocket().longValue();
+            sendfileData.keepAlive = keepAlive;
+            if (!((AprEndpoint)endpoint).getSendfile().add(sendfileData)) {
+                // Didn't send all of the data to sendfile.
+                if (sendfileData.socket == 0) {
+                    // The socket is no longer set. Something went wrong.
+                    // Close the connection. Too late to set status code.
                     if (log.isDebugEnabled()) {
-                        log.debug(sm.getString("http11processor.request.prepare"), t);
+                        log.debug(sm.getString(
+                                "http11processor.sendfile.error"));
                     }
-                    // 400 - Internal Server Error
-                    response.setStatus(400);
-                    adapter.log(request, response, 0);
                     error = true;
+                } else {
+                    // The sendfile Poller will add the socket to the main
+                    // Poller once sendfile processing is complete
+                    sendfileInProgress = true;
                 }
-            }
-
-            if (maxKeepAliveRequests == 1) {
-                keepAlive = false;
-            } else if (maxKeepAliveRequests > 0 &&
-                    socketWrapper.decrementKeepAlive() <= 0) {
-                keepAlive = false;
-            }
-
-            // Process the request in the adapter
-            if (!error) {
-                try {
-                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
-                    adapter.service(request, response);
-                    // Handle when the response was committed before a serious
-                    // error occurred.  Throwing a ServletException should both
-                    // set the status to 500 and set the errorException.
-                    // If we fail here, then the response is likely already
-                    // committed, so we can't try and set headers.
-                    if(keepAlive && !error) { // Avoid checking twice.
-                        error = response.getErrorException() != null ||
-                                (!isAsync() &&
-                                statusDropsConnection(response.getStatus()));
-                    }
-                } catch (InterruptedIOException e) {
-                    error = true;
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    log.error(sm.getString("http11processor.request.process"), t);
-                    // 500 - Internal Server Error
-                    response.setStatus(500);
-                    adapter.log(request, response, 0);
-                    error = true;
-                }
-            }
-
-            // Finish the handling of the request
-            if (!comet && !isAsync()) {
-                // If we know we are closing the connection, don't drain input.
-                // This way uploading a 100GB file doesn't tie up the thread 
-                // if the servlet has rejected it.
-                if(error)
-                    inputBuffer.setSwallowInput(false);
-                endRequest();
-            }
-
-            // If there was an error, make sure the request is counted as
-            // and error, and update the statistics counter
-            if (error) {
-                response.setStatus(500);
-            }
-            request.updateCounters();
-
-            if (!comet && !isAsync()) {
-                // Next request
-                inputBuffer.nextRequest();
-                outputBuffer.nextRequest();
-            }
-            
-            // Do sendfile as needed: add socket to sendfile and end
-            if (sendfileData != null && !error) {
-                sendfileData.socket = socketRef;
-                sendfileData.keepAlive = keepAlive;
-                if (!((AprEndpoint)endpoint).getSendfile().add(sendfileData)) {
-                    // Didn't send all of the data to sendfile.
-                    if (sendfileData.socket == 0) {
-                        // The socket is no longer set. Something went wrong.
-                        // Close the connection. Too late to set status code.
-                        if (log.isDebugEnabled()) {
-                            log.debug(sm.getString(
-                                    "http11processor.sendfile.error"));
-                        }
-                        error = true;
-                    } else {
-                        // The sendfile Poller will add the socket to the main
-                        // Poller once sendfile processing is complete
-                        sendfileInProgress = true;
-                    }
-                    break;
-                }
-            }
-            
-            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
-
-        }
-
-        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
-
-        if (error || endpoint.isPaused()) {
-            return SocketState.CLOSED;
-        } else if (comet  || isAsync()) {
-            return SocketState.LONG;
-        } else {
-            if (sendfileInProgress) {
-                return SocketState.SENDFILE;
-            } else {
-                return (openSocket) ? SocketState.OPEN : SocketState.CLOSED;
+                return true;
             }
         }
-        
-    }
-
-
-    @Override
-    protected boolean disableKeepAlive() {
         return false;
     }
 
@@ -633,6 +517,11 @@ public class Http11AprProcessor extends AbstractHttp11Processor<Long> {
     }
 
     @Override
+    protected void setSocketWrapper(SocketWrapper<Long> socketWrapper) {
+        this.socket = socketWrapper;
+    }
+
+    @Override
     protected AbstractInputBuffer<Long> getInputBuffer() {
         return inputBuffer;
     }
diff --git a/java/org/apache/coyote/http11/Http11AprProtocol.java b/java/org/apache/coyote/http11/Http11AprProtocol.java
index 47a6ac4..163c4a4 100644
--- a/java/org/apache/coyote/http11/Http11AprProtocol.java
+++ b/java/org/apache/coyote/http11/Http11AprProtocol.java
@@ -215,9 +215,9 @@ public class Http11AprProtocol extends AbstractHttp11Protocol {
                 boolean addToPoller) {
             processor.recycle();
             recycledProcessors.offer(processor);
-            if (addToPoller) {
+            if (addToPoller && proto.endpoint.isRunning()) {
                 ((AprEndpoint)proto.endpoint).getPoller().add(
-                        socket.getSocket().longValue());
+                        socket.getSocket().longValue(), true);
             }
         }
 
@@ -234,9 +234,9 @@ public class Http11AprProtocol extends AbstractHttp11Protocol {
 
             if (processor.isAsync()) {
                 socket.setAsync(true);
-            } else if (processor.comet) {
+            } else if (processor.comet && proto.endpoint.isRunning()) {
                 ((AprEndpoint) proto.endpoint).getCometPoller().add(
-                        socket.getSocket().longValue());
+                        socket.getSocket().longValue(), false);
             }
         }
 
diff --git a/java/org/apache/coyote/http11/Http11NioProcessor.java b/java/org/apache/coyote/http11/Http11NioProcessor.java
index afdddfb..d89f906 100644
--- a/java/org/apache/coyote/http11/Http11NioProcessor.java
+++ b/java/org/apache/coyote/http11/Http11NioProcessor.java
@@ -137,7 +137,7 @@ public class Http11NioProcessor extends AbstractHttp11Processor<NioChannel> {
                         if (comettimeout != null) attach.setTimeout(comettimeout.longValue());
                     } else {
                         //reset the timeout
-                        if (keepAlive && keepAliveTimeout>0) {
+                        if (keepAlive) {
                             attach.setTimeout(keepAliveTimeout);
                         } else {
                             attach.setTimeout(soTimeout);
@@ -177,7 +177,7 @@ public class Http11NioProcessor extends AbstractHttp11Processor<NioChannel> {
             long soTimeout = endpoint.getSoTimeout();
 
             //reset the timeout
-            if (keepAlive && keepAliveTimeout>0) {
+            if (keepAlive) {
                 attach.setTimeout(keepAliveTimeout);
             } else {
                 attach.setTimeout(soTimeout);
@@ -186,224 +186,102 @@ public class Http11NioProcessor extends AbstractHttp11Processor<NioChannel> {
     }
 
 
-    /**
-     * Process pipelined HTTP requests using the specified input and output
-     * streams.
-     *
-     * @param socketWrapper Socket from which the HTTP requests will be read
-     *               and the HTTP responses will be written.
-     *  
-     * @throws IOException error during an I/O operation
-     */
     @Override
-    public SocketState process(SocketWrapper<NioChannel> socketWrapper)
-        throws IOException {
-        RequestInfo rp = request.getRequestProcessor();
-        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
+    protected boolean disableKeepAlive() {
+        return false;
+    }
 
-        // Setting up the socket
-        this.socket = socketWrapper;
-        inputBuffer.init(socketWrapper, endpoint);
-        outputBuffer.init(socketWrapper, endpoint);
 
-        // Error flag
-        error = false;
-        keepAlive = true;
-        comet = false;
+    @Override
+    protected void setRequestLineReadTimeout() throws IOException {
+        // socket.setTimeout()
+        //     - timeout used by poller
+        // socket.getSocket().getIOChannel().socket().setSoTimeout()
+        //     - timeout used for blocking reads
+
+        // When entering the processing loop there will always be data to read
+        // so no point changing timeouts at this point
         
-        int soTimeout = endpoint.getSoTimeout();
-
-        if (disableKeepAlive()) {
-            socketWrapper.setKeepAliveLeft(0);
-        }
-
-        boolean keptAlive = false;
-        boolean openSocket = false;
-        boolean readComplete = true;
+        // For the second and subsequent executions of the processing loop, a
+        // non-blocking read is used so again no need to set the timeouts
         
-        while (!error && keepAlive && !comet && !isAsync() && !endpoint.isPaused()) {
-            //always default to our soTimeout
-            socketWrapper.setTimeout(soTimeout);
-            // Parsing the request header
-            try {
-                if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) {
-                    socketWrapper.getSocket().getIOChannel().socket().setSoTimeout(soTimeout);
-                }
-                if (!inputBuffer.parseRequestLine(keptAlive)) {
-                    // Haven't finished reading the request so keep the socket
-                    // open
-                    openSocket = true;
-                    // Check to see if we have read any of the request line yet
-                    if (inputBuffer.getParsingRequestLinePhase()<2) {
-                        // No data read, OK to recycle the processor
-                        // Continue to use keep alive timeout
-                        if (keepAliveTimeout>0) {
-                            socketWrapper.setTimeout(keepAliveTimeout);
-                        }
-                    } else {
-                        // Started to read request line. Need to keep processor
-                        // associated with socket
-                        readComplete = false;
-                    }
-                    if (endpoint.isPaused()) {
-                        // 503 - Service unavailable
-                        response.setStatus(503);
-                        adapter.log(request, response, 0);
-                        error = true;
-                    } else {
-                        break;
-                    }
-                }
-                if (!endpoint.isPaused()) {
-                    keptAlive = true;
-                    if ( !inputBuffer.parseHeaders() ) {
-                        //we've read part of the request, don't recycle it
-                        //instead associate it with the socket
-                        openSocket = true;
-                        readComplete = false;
-                        break;
-                    }
-                    request.setStartTime(System.currentTimeMillis());
-                    if (!disableUploadTimeout) { //only for body, not for request headers
-                        socketWrapper.getSocket().getIOChannel().socket().setSoTimeout(
-                                connectionUploadTimeout);
-                    }
-                }
-            } catch (IOException e) {
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("http11processor.header.parse"), e);
-                }
-                error = true;
-                break;
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("http11processor.header.parse"), t);
-                }
-                // 400 - Bad Request
-                response.setStatus(400);
-                adapter.log(request, response, 0);
-                error = true;
-            }
+        // Because NIO supports non-blocking reading of the request line and
+        // headers the timeouts need to be set when returning the socket to
+        // the poller rather than here.
+        
+        // NO-OP
+    }
 
-            if (!error) {
-                // Setting up filters, and parse some request headers
-                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
-                try {
-                    prepareRequest();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    if (log.isDebugEnabled()) {
-                        log.debug(sm.getString("http11processor.request.prepare"), t);
-                    }
-                    // 400 - Internal Server Error
-                    response.setStatus(400);
-                    adapter.log(request, response, 0);
-                    error = true;
-                }
-            }
-            
-            if (maxKeepAliveRequests == 1) {
-                keepAlive = false;
-            } else if (maxKeepAliveRequests > 0 &&
-                    socketWrapper.decrementKeepAlive() <= 0) {
-                keepAlive = false;
-            }
 
-            // Process the request in the adapter
-            if (!error) {
-                try {
-                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
-                    adapter.service(request, response);
-                    // Handle when the response was committed before a serious
-                    // error occurred.  Throwing a ServletException should both
-                    // set the status to 500 and set the errorException.
-                    // If we fail here, then the response is likely already
-                    // committed, so we can't try and set headers.
-                    if(keepAlive && !error) { // Avoid checking twice.
-                        error = response.getErrorException() != null ||
-                                (!isAsync() &&
-                                statusDropsConnection(response.getStatus()));
-                    }
-                    // Comet support
-                    SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
-                            socketWrapper.getSocket().getPoller().getSelector());
-                    if (key != null) {
-                        NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();
-                        if (attach != null)  {
-                            attach.setComet(comet);
-                            if (comet) {
-                                Integer comettimeout = (Integer) request.getAttribute("org.apache.tomcat.comet.timeout");
-                                if (comettimeout != null) attach.setTimeout(comettimeout.longValue());
-                            }
-                        }
-                    }
-                } catch (InterruptedIOException e) {
-                    error = true;
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    log.error(sm.getString("http11processor.request.process"), t);
-                    // 500 - Internal Server Error
-                    response.setStatus(500);
-                    adapter.log(request, response, 0);
-                    error = true;
-                }
+    @Override
+    protected boolean handleIncompleteRequestLineRead() {
+        // Haven't finished reading the request so keep the socket
+        // open
+        openSocket = true;
+        // Check to see if we have read any of the request line yet
+        if (inputBuffer.getParsingRequestLinePhase() < 2) {
+            if (socket.getLastAccess() > -1 || keptAlive) {
+                // Haven't read the request line and have previously processed a
+                // request. Must be keep-alive. Make sure poller uses keepAlive.
+                socket.setTimeout(endpoint.getKeepAliveTimeout());
             }
+        } else {
+            // Started to read request line. Need to keep processor
+            // associated with socket
+            readComplete = false;
+            // Make sure poller uses soTimeout from here onwards
+            socket.setTimeout(endpoint.getSoTimeout());
+        }
+        if (endpoint.isPaused()) {
+            // 503 - Service unavailable
+            response.setStatus(503);
+            adapter.log(request, response, 0);
+            error = true;
+        } else {
+            return true;
+        }
+        return false;
+    }
 
-            // Finish the handling of the request
-            if (!comet && !isAsync()) {
-                // If we know we are closing the connection, don't drain input.
-                // This way uploading a 100GB file doesn't tie up the thread 
-                // if the servlet has rejected it.
-                if(error)
-                    inputBuffer.setSwallowInput(false);
-                endRequest();
-            }
 
-            // If there was an error, make sure the request is counted as
-            // and error, and update the statistics counter
-            if (error) {
-                response.setStatus(500);
-            }
-            request.updateCounters();
+    @Override
+    protected void setSocketTimeout(int timeout) throws IOException {
+        socket.getSocket().getIOChannel().socket().setSoTimeout(timeout);
+    }
 
-            if (!comet && !isAsync()) {
-                // Next request
-                inputBuffer.nextRequest();
-                outputBuffer.nextRequest();
-            }
-            
-            // Do sendfile as needed: add socket to sendfile and end
-            if (sendfileData != null && !error) {
-                ((KeyAttachment) socketWrapper).setSendfileData(sendfileData);
-                sendfileData.keepAlive = keepAlive;
-                SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
-                        socketWrapper.getSocket().getPoller().getSelector());
-                //do the first write on this thread, might as well
-                openSocket = socketWrapper.getSocket().getPoller().processSendfile(key,
-                        (KeyAttachment) socketWrapper, true, true);
-                break;
+    
+    @Override
+    protected void setCometTimeouts(SocketWrapper<NioChannel> socketWrapper) {
+        // Comet support
+        SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
+                socketWrapper.getSocket().getPoller().getSelector());
+        if (key != null) {
+            NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();
+            if (attach != null)  {
+                attach.setComet(comet);
+                if (comet) {
+                    Integer comettimeout = (Integer) request.getAttribute("org.apache.tomcat.comet.timeout");
+                    if (comettimeout != null) attach.setTimeout(comettimeout.longValue());
+                }
             }
-
-
-            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
-
-        }//while
-
-        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
-        if (error || endpoint.isPaused()) {
-            return SocketState.CLOSED;
-        } else if (comet || isAsync()) {
-            return SocketState.LONG;
-        } else {
-            return (openSocket) ? (readComplete?SocketState.OPEN:SocketState.LONG) : SocketState.CLOSED;
         }
-
     }
 
 
     @Override
-    protected boolean disableKeepAlive() {
+    protected boolean breakKeepAliveLoop(
+            SocketWrapper<NioChannel> socketWrapper) {
+        // Do sendfile as needed: add socket to sendfile and end
+        if (sendfileData != null && !error) {
+            ((KeyAttachment) socketWrapper).setSendfileData(sendfileData);
+            sendfileData.keepAlive = keepAlive;
+            SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
+                    socketWrapper.getSocket().getPoller().getSelector());
+            //do the first write on this thread, might as well
+            openSocket = socketWrapper.getSocket().getPoller().processSendfile(key,
+                    (KeyAttachment) socketWrapper, true, true);
+            return true;
+        }
         return false;
     }
 
@@ -654,6 +532,11 @@ public class Http11NioProcessor extends AbstractHttp11Processor<NioChannel> {
     }
 
     @Override
+    protected void setSocketWrapper(SocketWrapper<NioChannel> socketWrapper) {
+        this.socket = socketWrapper;
+    }
+
+    @Override
     protected AbstractInputBuffer<NioChannel> getInputBuffer() {
         return inputBuffer;
     }
diff --git a/java/org/apache/coyote/http11/Http11NioProtocol.java b/java/org/apache/coyote/http11/Http11NioProtocol.java
index 1ff59ff..a0f2498 100644
--- a/java/org/apache/coyote/http11/Http11NioProtocol.java
+++ b/java/org/apache/coyote/http11/Http11NioProtocol.java
@@ -74,9 +74,6 @@ public class Http11NioProtocol extends AbstractHttp11JsseProtocol {
 
     // -------------------- Properties--------------------
     
-
-    private int socketCloseDelay=-1;
-    
     private Http11ConnectionHandler cHandler;
 
     // -------------------- Pool setup --------------------
@@ -96,8 +93,6 @@ public class Http11NioProtocol extends AbstractHttp11JsseProtocol {
     public long getSelectorTimeout() {
         return ((NioEndpoint)endpoint).getSelectorTimeout();
     }
-    // *
-
     
     public void setAcceptorThreadPriority(int threadPriority) {
         ((NioEndpoint)endpoint).setAcceptorThreadPriority(threadPriority);
@@ -125,14 +120,6 @@ public class Http11NioProtocol extends AbstractHttp11JsseProtocol {
     }
     
     // -------------------- Tcp setup --------------------
-    public int getSocketCloseDelay() {
-        return socketCloseDelay;
-    }
-
-    public void setSocketCloseDelay( int d ) {
-        socketCloseDelay=d;
-    }
-
     public void setOomParachute(int oomParachute) {
         ((NioEndpoint)endpoint).setOomParachute(oomParachute);
     }
diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java
index 25bbea3..e157284 100644
--- a/java/org/apache/coyote/http11/Http11Processor.java
+++ b/java/org/apache/coyote/http11/Http11Processor.java
@@ -18,16 +18,13 @@ package org.apache.coyote.http11;
 
 import java.io.EOFException;
 import java.io.IOException;
-import java.io.InterruptedIOException;
 import java.net.InetAddress;
 import java.net.Socket;
 
 import org.apache.coyote.ActionCode;
-import org.apache.coyote.RequestInfo;
 import org.apache.coyote.http11.filters.BufferedInputFilter;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
 import org.apache.tomcat.util.net.JIoEndpoint;
 import org.apache.tomcat.util.net.SSLSupport;
@@ -121,265 +118,101 @@ public class Http11Processor extends AbstractHttp11Processor<Socket> {
     }
 
 
-    /**
-     * Process pipelined HTTP requests using the specified input and output
-     * streams.
-     *
-     * @param socketWrapper Socket from which the HTTP requests will be read
-     *               and the HTTP responses will be written.
-     *  
-     * @throws IOException error during an I/O operation
-     */
     @Override
-    public SocketState process(SocketWrapper<Socket> socketWrapper)
-        throws IOException {
-        RequestInfo rp = request.getRequestProcessor();
-        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
-
-        // Setting up the I/O
-        this.socket = socketWrapper;
-        inputBuffer.init(socketWrapper, endpoint);
-        outputBuffer.init(socketWrapper, endpoint);
-
-        // Error flag
-        error = false;
-        keepAlive = true;
-        comet = false;
-
-        int soTimeout = endpoint.getSoTimeout();
-
-        if (disableKeepAlive()) {
-            socketWrapper.setKeepAliveLeft(0);
+    protected boolean disableKeepAlive() {
+        int threadRatio = -1;   
+        // These may return zero or negative values
+        // Only calculate a thread ratio when both are >0 to ensure we get a
+        // sensible result
+        int maxThreads, threadsBusy;
+        if ((maxThreads = endpoint.getMaxThreads()) > 0
+                && (threadsBusy = endpoint.getCurrentThreadsBusy()) > 0) {
+            threadRatio = (threadsBusy * 100) / maxThreads;
         }
-
-        try {
-            socket.getSocket().setSoTimeout(soTimeout);
-        } catch (Throwable t) {
-            ExceptionUtils.handleThrowable(t);
-            log.debug(sm.getString("http11processor.socket.timeout"), t);
-            error = true;
+        // Disable keep-alive if we are running low on threads      
+        if (threadRatio > getDisableKeepAlivePercentage()) {     
+            return true;
         }
+        
+        return false;
+    }
 
-        boolean keptAlive = socketWrapper.isKeptAlive();
-
-        while (!error && keepAlive && !endpoint.isPaused()) {
 
-            // Parsing the request header
-            try {
-                int standardTimeout = 0;
-                if (keptAlive) {
-                    if (keepAliveTimeout > 0) {
-                        standardTimeout = keepAliveTimeout;
-                    } else if (soTimeout > 0) {
-                        standardTimeout = soTimeout;
-                    }
-                }
-                /*
-                 * When there is no data in the buffer and this is not the first
-                 * request on this connection and timeouts are being used the
-                 * first read for this request may need a different timeout to
-                 * take account of time spent waiting for a processing thread.
-                 * 
-                 * This is a little hacky but better than exposing the socket
-                 * and the timeout info to the InputBuffer
-                 */
-                if (inputBuffer.lastValid == 0 &&
-                        socketWrapper.getLastAccess() > -1 &&
-                        standardTimeout > 0) {
-
-                    long queueTime = System.currentTimeMillis() -
-                            socketWrapper.getLastAccess();
-                    int firstReadTimeout;
-                    if (queueTime >= standardTimeout) {
-                        // Queued for longer than timeout but there might be
-                        // data so use shortest possible timeout
-                        firstReadTimeout = 1;
-                    } else {
-                        // Cast is safe since queueTime must be less than
-                        // standardTimeout which is an int
-                        firstReadTimeout = standardTimeout - (int) queueTime;
-                    }
-                    socket.getSocket().setSoTimeout(firstReadTimeout);
-                    if (!inputBuffer.fill()) {
-                        throw new EOFException(sm.getString("iib.eof.error"));
-                    }
-                }
-                if (standardTimeout > 0) {
-                    socket.getSocket().setSoTimeout(standardTimeout);
-                }
+    @Override
+    protected void setRequestLineReadTimeout() throws IOException {
+        
+        /*
+         * When there is no data in the buffer and this is not the first
+         * request on this connection and timeouts are being used the
+         * first read for this request may need a different timeout to
+         * take account of time spent waiting for a processing thread.
+         * 
+         * This is a little hacky but better than exposing the socket
+         * and the timeout info to the InputBuffer
+         */
+        if (inputBuffer.lastValid == 0 && socket.getLastAccess() > -1) {
+            int firstReadTimeout;
+            if (keepAliveTimeout == -1) {
+                firstReadTimeout = 0;
+            } else {
+                long queueTime =
+                    System.currentTimeMillis() - socket.getLastAccess();
 
-                inputBuffer.parseRequestLine(false);
-                if (endpoint.isPaused()) {
-                    // 503 - Service unavailable
-                    response.setStatus(503);
-                    adapter.log(request, response, 0);
-                    error = true;
+                if (queueTime >= keepAliveTimeout) {
+                    // Queued for longer than timeout but there might be
+                    // data so use shortest possible timeout
+                    firstReadTimeout = 1;
                 } else {
-                    request.setStartTime(System.currentTimeMillis());
-                    keptAlive = true;
-                    if (disableUploadTimeout) {
-                        socket.getSocket().setSoTimeout(soTimeout);
-                    } else {
-                        socket.getSocket().setSoTimeout(connectionUploadTimeout);
-                    }
-                    inputBuffer.parseHeaders();
-                }
-            } catch (IOException e) {
-                error = true;
-                break;
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("http11processor.header.parse"), t);
-                }
-                // 400 - Bad Request
-                response.setStatus(400);
-                adapter.log(request, response, 0);
-                error = true;
-            }
-
-            if (!error) {
-                // Setting up filters, and parse some request headers
-                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
-                try {
-                    prepareRequest();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    if (log.isDebugEnabled()) {
-                        log.debug(sm.getString("http11processor.request.prepare"), t);
-                    }
-                    // 400 - Internal Server Error
-                    response.setStatus(400);
-                    adapter.log(request, response, 0);
-                    error = true;
+                    // Cast is safe since queueTime must be less than
+                    // keepAliveTimeout which is an int
+                    firstReadTimeout = keepAliveTimeout - (int) queueTime;
                 }
             }
-
-            if (maxKeepAliveRequests == 1) {
-                keepAlive = false;
-            } else if (maxKeepAliveRequests > 0 &&
-                    socketWrapper.decrementKeepAlive() <= 0) {
-                keepAlive = false;
-            }
-
-            // Process the request in the adapter
-            if (!error) {
-                try {
-                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
-                    adapter.service(request, response);
-                    // Handle when the response was committed before a serious
-                    // error occurred.  Throwing a ServletException should both
-                    // set the status to 500 and set the errorException.
-                    // If we fail here, then the response is likely already
-                    // committed, so we can't try and set headers.
-                    if(keepAlive && !error) { // Avoid checking twice.
-                        error = response.getErrorException() != null ||
-                                (!isAsync() &&
-                                statusDropsConnection(response.getStatus()));
-                    }
-
-                } catch (InterruptedIOException e) {
-                    error = true;
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    log.error(sm.getString("http11processor.request.process"), t);
-                    // 500 - Internal Server Error
-                    response.setStatus(500);
-                    adapter.log(request, response, 0);
-                    error = true;
-                }
-            }
-
-            // Finish the handling of the request
-            try {
-                rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
-                // If we know we are closing the connection, don't drain input.
-                // This way uploading a 100GB file doesn't tie up the thread 
-                // if the servlet has rejected it.
-                
-                if(error && !isAsync())
-                    inputBuffer.setSwallowInput(false);
-                if (!isAsync())
-                    endRequest();
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                log.error(sm.getString("http11processor.request.finish"), t);
-                // 500 - Internal Server Error
-                response.setStatus(500);
-                adapter.log(request, response, 0);
-                error = true;
-            }
-            try {
-                rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                log.error(sm.getString("http11processor.response.finish"), t);
-                error = true;
+            socket.getSocket().setSoTimeout(firstReadTimeout);
+            if (!inputBuffer.fill()) {
+                throw new EOFException(sm.getString("iib.eof.error"));
             }
+            // Once the first byte has been read, the standard timeout should be
+            // used so restore it here.
+            socket.getSocket().setSoTimeout(endpoint.getSoTimeout());
+        }
+    }
 
-            // If there was an error, make sure the request is counted as
-            // and error, and update the statistics counter
-            if (error) {
-                response.setStatus(500);
-            }
-            request.updateCounters();
 
-            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
+    @Override
+    protected boolean handleIncompleteRequestLineRead() {
+        // Not used with BIO since it uses blocking reads
+        return false;
+    }
 
-            // Don't reset the param - we'll see it as ended. Next request
-            // will reset it
-            // thrA.setParam(null);
-            // Next request
-            if (!isAsync() || error) {
-                inputBuffer.nextRequest();
-                outputBuffer.nextRequest();
-            }
 
-            // If we don't have a pipe-lined request allow this thread to be
-            // used by another connection
-            if (isAsync() || error || inputBuffer.lastValid == 0) {
-                break;
-            }
-        }
-
-        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
-        if (error || endpoint.isPaused()) {
-            return SocketState.CLOSED;
-        } else if (isAsync()) {
-            return SocketState.LONG;
-        } else {
-            if (!keepAlive) {
-                return SocketState.CLOSED;
-            } else {
-                return SocketState.OPEN;
-            }
-        } 
+    @Override
+    protected void setSocketTimeout(int timeout) throws IOException {
+        socket.getSocket().setSoTimeout(timeout);
     }
     
     
     @Override
-    protected boolean disableKeepAlive() {
-        int threadRatio = -1;   
-        // These may return zero or negative values     
-        // Only calculate a thread ratio when both are >0 to ensure we get a    
-        // sensible result      
-        if (endpoint.getCurrentThreadsBusy() >0 &&      
-                endpoint.getMaxThreads() >0) {      
-            threadRatio = (endpoint.getCurrentThreadsBusy() * 100)      
-                    / endpoint.getMaxThreads();     
-        }   
-        // Disable keep-alive if we are running low on threads      
-        if (threadRatio > getDisableKeepAlivePercentage()) {     
+    protected void setCometTimeouts(SocketWrapper<Socket> socketWrapper) {
+        // NO-OP for BIO
+    }
+
+
+    @Override
+    protected boolean breakKeepAliveLoop(SocketWrapper<Socket> socketWrapper) {
+        openSocket = keepAlive;
+        // If we don't have a pipe-lined request allow this thread to be
+        // used by another connection
+        if (inputBuffer.lastValid == 0) {
             return true;
         }
-        
         return false;
     }
 
-
+    
     @Override
     protected void resetTimeouts() {
-        // NOOP for APR
+        // NOOP for BIO
     }
 
 
@@ -564,6 +397,11 @@ public class Http11Processor extends AbstractHttp11Processor<Socket> {
     }
 
     @Override
+    protected void setSocketWrapper(SocketWrapper<Socket> socketWrapper) {
+        this.socket = socketWrapper;
+    }
+
+    @Override
     protected AbstractInputBuffer<Socket> getInputBuffer() {
         return inputBuffer;
     }
diff --git a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java
index 938b7cf..dca3fae 100644
--- a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java
+++ b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java
@@ -176,7 +176,6 @@ public class InternalNioOutputBuffer extends AbstractOutputBuffer<NioChannel> {
             if ( selector != null ) pool.put(selector);
         }
         if ( block ) bytebuffer.clear(); //only clear
-        this.total = 0;
         return written;
     } 
 
@@ -212,7 +211,6 @@ public class InternalNioOutputBuffer extends AbstractOutputBuffer<NioChannel> {
 
     }
 
-    private int total = 0;
     private synchronized void addToBB(byte[] buf, int offset, int length) throws IOException {
         while (length > 0) {
             int thisTime = length;
@@ -227,7 +225,6 @@ public class InternalNioOutputBuffer extends AbstractOutputBuffer<NioChannel> {
             socket.getBufHandler().getWriteBuffer().put(buf, offset, thisTime);
             length = length - thisTime;
             offset = offset + thisTime;
-            total += thisTime;
         }
         NioEndpoint.KeyAttachment ka = (NioEndpoint.KeyAttachment)socket.getAttachment(false);
         if ( ka!= null ) ka.access();//prevent timeouts for just doing client writes
diff --git a/java/org/apache/el/parser/ELParser.java b/java/org/apache/el/parser/ELParser.java
index c594ec0..e29b082 100644
--- a/java/org/apache/el/parser/ELParser.java
+++ b/java/org/apache/el/parser/ELParser.java
@@ -3,6 +3,8 @@ package org.apache.el.parser;
 import java.io.StringReader;
 
 import javax.el.ELException;
+
+ at SuppressWarnings("all") // Ignore warnings in generated code
 public class ELParser/*@bgen(jjtree)*/implements ELParserTreeConstants, ELParserConstants {/*@bgen(jjtree)*/
   protected JJTELParserState jjtree = new JJTELParserState();public static Node parse(String ref) throws ELException
     {
diff --git a/java/org/apache/el/parser/ELParserTokenManager.java b/java/org/apache/el/parser/ELParserTokenManager.java
index 92fdae8..e277cf8 100644
--- a/java/org/apache/el/parser/ELParserTokenManager.java
+++ b/java/org/apache/el/parser/ELParserTokenManager.java
@@ -2,6 +2,7 @@
 package org.apache.el.parser;
 
 /** Token Manager. */
+ at SuppressWarnings("all") // Ignore warnings in generated code
 public class ELParserTokenManager implements ELParserConstants
 {
 
diff --git a/java/org/apache/el/parser/JJTELParserState.java b/java/org/apache/el/parser/JJTELParserState.java
index 9615b87..3ba4d77 100644
--- a/java/org/apache/el/parser/JJTELParserState.java
+++ b/java/org/apache/el/parser/JJTELParserState.java
@@ -1,6 +1,7 @@
 /* Generated By:JavaCC: Do not edit this line. JJTELParserState.java Version 5.0 */
 package org.apache.el.parser;
 
+ at SuppressWarnings("all") // Ignore warnings in generated code
 public class JJTELParserState {
   private java.util.List<Node> nodes;
   private java.util.List<Integer> marks;
diff --git a/java/org/apache/el/parser/SimpleCharStream.java b/java/org/apache/el/parser/SimpleCharStream.java
index e484965..0e7f31e 100644
--- a/java/org/apache/el/parser/SimpleCharStream.java
+++ b/java/org/apache/el/parser/SimpleCharStream.java
@@ -6,7 +6,7 @@ package org.apache.el.parser;
  * An implementation of interface CharStream, where the stream is assumed to
  * contain only ASCII characters (without unicode processing).
  */
-
+ at SuppressWarnings("all") // Ignore warnings in generated code
 public class SimpleCharStream
 {
 /** Whether parser is static. */
diff --git a/java/org/apache/el/parser/Token.java b/java/org/apache/el/parser/Token.java
index 3aa02cc..a3fe367 100644
--- a/java/org/apache/el/parser/Token.java
+++ b/java/org/apache/el/parser/Token.java
@@ -5,7 +5,7 @@ package org.apache.el.parser;
 /**
  * Describes the input token stream.
  */
-
+ at SuppressWarnings("all") // Ignore warnings in generated code
 public class Token implements java.io.Serializable {
 
   /**
diff --git a/java/org/apache/el/parser/TokenMgrError.java b/java/org/apache/el/parser/TokenMgrError.java
index 2964ed0..7fee656 100644
--- a/java/org/apache/el/parser/TokenMgrError.java
+++ b/java/org/apache/el/parser/TokenMgrError.java
@@ -3,6 +3,7 @@
 package org.apache.el.parser;
 
 /** Token Manager Error. */
+ at SuppressWarnings("all") // Ignore warnings in generated code
 public class TokenMgrError extends Error
 {
 
diff --git a/java/org/apache/jasper/compiler/JspRuntimeContext.java b/java/org/apache/jasper/compiler/JspRuntimeContext.java
index bdc6822..893541a 100644
--- a/java/org/apache/jasper/compiler/JspRuntimeContext.java
+++ b/java/org/apache/jasper/compiler/JspRuntimeContext.java
@@ -57,7 +57,7 @@ import org.apache.juli.logging.LogFactory;
  * Only used if a web application context is a directory.
  *
  * @author Glenn L. Nielsen
- * @version $Revision: 1081391 $
+ * @version $Revision: 1172614 $
  */
 public final class JspRuntimeContext {
 
@@ -250,6 +250,7 @@ public final class JspRuntimeContext {
                                                replaced.getJspUri(), context.getContextPath()));
             }
             unloadJspServletWrapper(replaced);
+            entry.clearReplaced();
         }
         return entry;
     }
diff --git a/java/org/apache/jasper/util/FastRemovalDequeue.java b/java/org/apache/jasper/util/FastRemovalDequeue.java
index 74a65fd..b43d7e4 100644
--- a/java/org/apache/jasper/util/FastRemovalDequeue.java
+++ b/java/org/apache/jasper/util/FastRemovalDequeue.java
@@ -284,6 +284,10 @@ public class FastRemovalDequeue<T> {
             this.replaced = replaced;
         }
 
+        public final void clearReplaced() {
+            this.replaced = null;
+        }
+        
         private final Entry getNext() {
             return next;
         }
diff --git a/java/org/apache/juli/OneLineFormatter.java b/java/org/apache/juli/OneLineFormatter.java
index f090c73..1ee6557 100644
--- a/java/org/apache/juli/OneLineFormatter.java
+++ b/java/org/apache/juli/OneLineFormatter.java
@@ -76,6 +76,12 @@ public class OneLineFormatter extends Formatter {
         sb.append(' ');
         sb.append(record.getLevel());
 
+        // Thread
+        sb.append(' ');
+        sb.append('[');
+        sb.append(Thread.currentThread().getName());
+        sb.append(']');
+
         // Source
         sb.append(' ');
         sb.append(record.getSourceClassName());
diff --git a/java/org/apache/naming/NamingContext.java b/java/org/apache/naming/NamingContext.java
index cabfd8d..ae2de7f 100644
--- a/java/org/apache/naming/NamingContext.java
+++ b/java/org/apache/naming/NamingContext.java
@@ -44,7 +44,7 @@ import javax.naming.spi.NamingManager;
  * Catalina JNDI Context implementation.
  *
  * @author Remy Maucherat
- * @version $Id: NamingContext.java 1033925 2010-11-11 13:00:52Z markt $
+ * @version $Id: NamingContext.java 1163633 2011-08-31 14:20:17Z markt $
  */
 public class NamingContext implements Context {
 
@@ -743,8 +743,8 @@ public class NamingContext implements Context {
      * @exception NamingException if a naming exception is encountered
      */
     @Override
-    public void close()
-        throws NamingException {
+    public void close() throws NamingException {
+        checkWritable();
         env.clear();
     }
 
diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java
index 3090120..6576e3d 100644
--- a/java/org/apache/tomcat/util/digester/Digester.java
+++ b/java/org/apache/tomcat/util/digester/Digester.java
@@ -102,7 +102,7 @@ public class Digester extends DefaultHandler {
                     initialized = true;
                 } catch (Throwable t) {
                     ExceptionUtils.handleThrowable(t);
-                    LogFactory.getLog("org.apache.commons.digester.Digester").
+                    LogFactory.getLog("org.apache.tomcat.util.digester.Digester").
                         error("Unable to load property source["+className+"].",t);
                 }
             }
@@ -330,14 +330,14 @@ public class Digester extends DefaultHandler {
      * The Log to which most logging calls will be made.
      */
     protected Log log =
-        LogFactory.getLog("org.apache.commons.digester.Digester");
+        LogFactory.getLog("org.apache.tomcat.util.digester.Digester");
 
 
     /**
      * The Log to which all SAX event related logging calls will be made.
      */
     protected Log saxLog =
-        LogFactory.getLog("org.apache.commons.digester.Digester.sax");
+        LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax");
     
         
     /** Stacks used for interrule communication, indexed by name String */
@@ -2530,8 +2530,8 @@ public class Digester extends DefaultHandler {
             return;
         }
 
-        log = LogFactory.getLog("org.apache.commons.digester.Digester");
-        saxLog = LogFactory.getLog("org.apache.commons.digester.Digester.sax");
+        log = LogFactory.getLog("org.apache.tomcat.util.digester.Digester");
+        saxLog = LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax");
 
         // Perform lazy configuration as needed
         initialize(); // call hook method for subclasses that want to be initialized once only
diff --git a/java/org/apache/tomcat/util/digester/GenericParser.java b/java/org/apache/tomcat/util/digester/GenericParser.java
index f75e671..02e41a4 100644
--- a/java/org/apache/tomcat/util/digester/GenericParser.java
+++ b/java/org/apache/tomcat/util/digester/GenericParser.java
@@ -41,7 +41,7 @@ public class GenericParser{
      * The Log to which all SAX event related logging calls will be made.
      */
     private static final Log log =
-        LogFactory.getLog("org.apache.commons.digester.Digester.sax");
+        LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax");
 
     /**
      * The JAXP 1.2 property required to set up the schema location.
diff --git a/java/org/apache/tomcat/util/digester/XercesParser.java b/java/org/apache/tomcat/util/digester/XercesParser.java
index 5abdd74..b337539 100644
--- a/java/org/apache/tomcat/util/digester/XercesParser.java
+++ b/java/org/apache/tomcat/util/digester/XercesParser.java
@@ -46,7 +46,7 @@ public class XercesParser{
      * The Log to which all SAX event related logging calls will be made.
      */
     private static final Log log =
-        LogFactory.getLog("org.apache.commons.digester.Digester.sax");
+        LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax");
 
 
     /**
diff --git a/java/org/apache/tomcat/util/modeler/BaseModelMBean.java b/java/org/apache/tomcat/util/modeler/BaseModelMBean.java
index 251a42c..7d5145b 100644
--- a/java/org/apache/tomcat/util/modeler/BaseModelMBean.java
+++ b/java/org/apache/tomcat/util/modeler/BaseModelMBean.java
@@ -499,6 +499,8 @@ public class BaseModelMBean implements DynamicMBean, MBeanRegistration, ModelMBe
      *
      * @exception InstanceNotFoundException if the managed resource object
      *  cannot be found
+     * @exception InvalidTargetObjectTypeException if the managed resource
+     *  object is of the wrong type
      * @exception MBeanException if the initializer of the object throws
      *  an exception
      * @exception RuntimeOperationsException if the managed resource or the
diff --git a/java/org/apache/tomcat/util/modeler/ManagedBean.java b/java/org/apache/tomcat/util/modeler/ManagedBean.java
index 768771d..b19e753 100644
--- a/java/org/apache/tomcat/util/modeler/ManagedBean.java
+++ b/java/org/apache/tomcat/util/modeler/ManagedBean.java
@@ -42,7 +42,7 @@ import javax.management.ServiceNotFoundException;
  * descriptor.</p>
  *
  * @author Craig R. McClanahan
- * @version $Id: ManagedBean.java 1038846 2010-11-24 22:08:38Z markt $
+ * @version $Id: ManagedBean.java 1176157 2011-09-27 01:21:08Z kkolinko $
  */
 
 public class ManagedBean implements java.io.Serializable {
@@ -483,148 +483,141 @@ public class ManagedBean implements java.io.Serializable {
     }
 
     Method getGetter(String aname, BaseModelMBean mbean, Object resource) 
-            throws AttributeNotFoundException, MBeanException, ReflectionException {
-        // TODO: do we need caching ? JMX is for management, it's not supposed to require lots of performance.
-        Method m=null; // (Method)getAttMap.get( name );
-
-        if( m==null ) {
-            AttributeInfo attrInfo = attributes.get(aname);
-            // Look up the actual operation to be used
-            if (attrInfo == null)
-                throw new AttributeNotFoundException(" Cannot find attribute " + aname + " for " + resource);
-            
-            String getMethod = attrInfo.getGetMethod();
-            if (getMethod == null)
-                throw new AttributeNotFoundException("Cannot find attribute " + aname + " get method name");
-
-            Object object = null;
-            NoSuchMethodException exception = null;
+            throws AttributeNotFoundException, ReflectionException {
+
+        Method m = null;
+
+        AttributeInfo attrInfo = attributes.get(aname);
+        // Look up the actual operation to be used
+        if (attrInfo == null)
+            throw new AttributeNotFoundException(" Cannot find attribute " + aname + " for " + resource);
+        
+        String getMethod = attrInfo.getGetMethod();
+        if (getMethod == null)
+            throw new AttributeNotFoundException("Cannot find attribute " + aname + " get method name");
+
+        Object object = null;
+        NoSuchMethodException exception = null;
+        try {
+            object = mbean;
+            m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
+        } catch (NoSuchMethodException e) {
+            exception = e;
+        }
+        if( m== null && resource != null ) {
             try {
-                object = mbean;
+                object = resource;
                 m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
+                exception=null;
             } catch (NoSuchMethodException e) {
                 exception = e;
             }
-            if( m== null && resource != null ) {
-                try {
-                    object = resource;
-                    m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG);
-                    exception=null;
-                } catch (NoSuchMethodException e) {
-                    exception = e;
-                }
-            }
-            if( exception != null )
-                throw new ReflectionException(exception,
-                                              "Cannot find getter method " + getMethod);
-            //getAttMap.put( name, m );
         }
+        if( exception != null )
+            throw new ReflectionException(exception,
+                                          "Cannot find getter method " + getMethod);
 
         return m;
     }
 
     public Method getSetter(String aname, BaseModelMBean bean, Object resource) 
-            throws AttributeNotFoundException, MBeanException, ReflectionException {
-        // Cache may be needed for getters, but it is a really bad idea for setters, this is far 
-        // less frequent.
-        Method m=null;//(Method)setAttMap.get( name );
+            throws AttributeNotFoundException, ReflectionException {
 
-        if( m==null ) {
-            AttributeInfo attrInfo = attributes.get(aname);
-            if (attrInfo == null)
-                throw new AttributeNotFoundException(" Cannot find attribute " + aname);
+        Method m = null;
 
-            // Look up the actual operation to be used
-            String setMethod = attrInfo.getSetMethod();
-            if (setMethod == null)
-                throw new AttributeNotFoundException("Cannot find attribute " + aname + " set method name");
+        AttributeInfo attrInfo = attributes.get(aname);
+        if (attrInfo == null)
+            throw new AttributeNotFoundException(" Cannot find attribute " + aname);
 
-            String argType=attrInfo.getType();
+        // Look up the actual operation to be used
+        String setMethod = attrInfo.getSetMethod();
+        if (setMethod == null)
+            throw new AttributeNotFoundException("Cannot find attribute " + aname + " set method name");
 
-            Class<?> signature[] =
-                new Class[] { BaseModelMBean.getAttributeClass( argType ) };
+        String argType=attrInfo.getType();
 
-            Object object = null;
-            NoSuchMethodException exception = null;
+        Class<?> signature[] =
+            new Class[] { BaseModelMBean.getAttributeClass( argType ) };
+
+        Object object = null;
+        NoSuchMethodException exception = null;
+        try {
+            object = bean;
+            m = object.getClass().getMethod(setMethod, signature);
+        } catch (NoSuchMethodException e) {
+            exception = e;
+        }
+        if( m== null && resource != null ) {
             try {
-                object = bean;
+                object = resource;
                 m = object.getClass().getMethod(setMethod, signature);
+                exception=null;
             } catch (NoSuchMethodException e) {
                 exception = e;
             }
-            if( m== null && resource != null ) {
-                try {
-                    object = resource;
-                    m = object.getClass().getMethod(setMethod, signature);
-                    exception=null;
-                } catch (NoSuchMethodException e) {
-                    exception = e;
-                }
-            }
-            if( exception != null )
-                throw new ReflectionException(exception,
-                                              "Cannot find setter method " + setMethod +
-                        " " + resource);
-            //setAttMap.put( name, m );
         }
+        if( exception != null )
+            throw new ReflectionException(exception,
+                                          "Cannot find setter method " + setMethod +
+                    " " + resource);
 
         return m;
     }
 
     public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource) 
             throws MBeanException, ReflectionException {
+
         Method method = null;
-        if (method == null) {
-            if (params == null)
-                params = new Object[0];
-            if (signature == null)
-                signature = new String[0];
-            if (params.length != signature.length)
-                throw new RuntimeOperationsException(
-                        new IllegalArgumentException(
-                                "Inconsistent arguments and signature"),
-                        "Inconsistent arguments and signature");
-
-            // Acquire the ModelMBeanOperationInfo information for
-            // the requested operation
-            OperationInfo opInfo = operations.get(aname);
-            if (opInfo == null)
-                throw new MBeanException(new ServiceNotFoundException(
-                        "Cannot find operation " + aname),
-                        "Cannot find operation " + aname);
-
-            // Prepare the signature required by Java reflection APIs
-            // FIXME - should we use the signature from opInfo?
-            Class<?> types[] = new Class[signature.length];
-            for (int i = 0; i < signature.length; i++) {
-                types[i] = BaseModelMBean.getAttributeClass(signature[i]);
-            }
+        
+        if (params == null)
+            params = new Object[0];
+        if (signature == null)
+            signature = new String[0];
+        if (params.length != signature.length)
+            throw new RuntimeOperationsException(
+                    new IllegalArgumentException(
+                            "Inconsistent arguments and signature"),
+                    "Inconsistent arguments and signature");
+
+        // Acquire the ModelMBeanOperationInfo information for
+        // the requested operation
+        OperationInfo opInfo = operations.get(aname);
+        if (opInfo == null)
+            throw new MBeanException(new ServiceNotFoundException(
+                    "Cannot find operation " + aname),
+                    "Cannot find operation " + aname);
+
+        // Prepare the signature required by Java reflection APIs
+        // FIXME - should we use the signature from opInfo?
+        Class<?> types[] = new Class[signature.length];
+        for (int i = 0; i < signature.length; i++) {
+            types[i] = BaseModelMBean.getAttributeClass(signature[i]);
+        }
 
-            // Locate the method to be invoked, either in this MBean itself
-            // or in the corresponding managed resource
-            // FIXME - Accessible methods in superinterfaces?
-            Object object = null;
-            Exception exception = null;
-            try {
-                object = bean;
+        // Locate the method to be invoked, either in this MBean itself
+        // or in the corresponding managed resource
+        // FIXME - Accessible methods in superinterfaces?
+        Object object = null;
+        Exception exception = null;
+        try {
+            object = bean;
+            method = object.getClass().getMethod(aname, types);
+        } catch (NoSuchMethodException e) {
+            exception = e;
+        }
+        try {
+            if ((method == null) && (resource != null)) {
+                object = resource;
                 method = object.getClass().getMethod(aname, types);
-            } catch (NoSuchMethodException e) {
-                exception = e;
             }
-            try {
-                if ((method == null) && (resource != null)) {
-                    object = resource;
-                    method = object.getClass().getMethod(aname, types);
-                }
-            } catch (NoSuchMethodException e) {
-                exception = e;
-            }
-            if (method == null) {
-                throw new ReflectionException(exception, "Cannot find method "
-                        + aname + " with this signature");
-            }
-            // invokeAttMap.put(mkey, method);
+        } catch (NoSuchMethodException e) {
+            exception = e;
+        }
+        if (method == null) {
+            throw new ReflectionException(exception, "Cannot find method "
+                    + aname + " with this signature");
         }
+
         return method;
     }
 
diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java
index 4e8d858..dd4d00e 100644
--- a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java
+++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java
@@ -44,7 +44,7 @@ public class MbeansDescriptorsDigesterSource extends ModelerSource
     List<ObjectName> mbeans = new ArrayList<ObjectName>();
     protected static volatile Digester digester = null;
     
-    protected static Digester createDigester(Registry registry) {
+    protected static Digester createDigester() {
 
         Digester digester = new Digester();
         digester.setNamespaceAware(false);
@@ -223,7 +223,7 @@ public class MbeansDescriptorsDigesterSource extends ModelerSource
         InputStream stream = (InputStream) source;
 
         if (digester == null) {
-            digester = createDigester(registry);
+            digester = createDigester();
         }
         ArrayList<ManagedBean> loadedMbeans = new ArrayList<ManagedBean>();
         
diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansSource.java
index b244ac0..a9e4a0a 100644
--- a/java/org/apache/tomcat/util/modeler/modules/MbeansSource.java
+++ b/java/org/apache/tomcat/util/modeler/modules/MbeansSource.java
@@ -340,8 +340,7 @@ public class MbeansSource extends ModelerSource implements MbeansSourceMBean
                         " " + value);
             ObjectName oname=new ObjectName(objectName);
             // find the type
-            if( type==null )
-                type=registry.getType(  oname, attName );
+            type=registry.getType(  oname, attName );
 
             if( type==null ) {
                 log.info("Can't find attribute " + objectName + " " + attName );
diff --git a/java/org/apache/tomcat/util/net/AbstractEndpoint.java b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
index f606817..27ef98b 100644
--- a/java/org/apache/tomcat/util/net/AbstractEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
@@ -170,12 +170,18 @@ public abstract class AbstractEndpoint {
     private BindState bindState = BindState.UNBOUND;
 
     /**
-     * Keepalive timeout, if lesser or equal to 0 then soTimeout will be used.
+     * Keepalive timeout, if not set the soTimeout is used.
      */
-    private int keepAliveTimeout = -1;
-    public int getKeepAliveTimeout() { return keepAliveTimeout;}
+    private Integer keepAliveTimeout = null;
+    public int getKeepAliveTimeout() {
+        if (keepAliveTimeout == null) {
+            return getSoTimeout();
+        } else {
+            return keepAliveTimeout.intValue();
+        }
+    }
     public void setKeepAliveTimeout(int keepAliveTimeout) {
-        this.keepAliveTimeout = keepAliveTimeout;
+        this.keepAliveTimeout = Integer.valueOf(keepAliveTimeout);
     }
 
 
@@ -559,9 +565,12 @@ public abstract class AbstractEndpoint {
 
     protected abstract Log getLog();
     // Flags to indicate optional feature support
+    // Some of these are always hard-coded, some are hard-coded to false (i.e.
+    // the endpoint does not support them) and some are configurable.
     public abstract boolean getUseSendfile();
     public abstract boolean getUseComet();
     public abstract boolean getUseCometTimeout();
+    public abstract boolean getUsePolling();
     
     protected LimitLatch initializeConnectionLatch() {
         if (connectionLimitLatch==null) {
diff --git a/java/org/apache/tomcat/util/net/AprEndpoint.java b/java/org/apache/tomcat/util/net/AprEndpoint.java
index 4bc9a9a..7534cfb 100644
--- a/java/org/apache/tomcat/util/net/AprEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AprEndpoint.java
@@ -160,6 +160,8 @@ public class AprEndpoint extends AbstractEndpoint {
     public boolean getUseComet() { return useComet; }
     @Override
     public boolean getUseCometTimeout() { return false; } // Not supported
+    @Override
+    public boolean getUsePolling() { return true; } // Always supported
 
 
     /**
@@ -750,8 +752,7 @@ public class AprEndpoint extends AbstractEndpoint {
                 Socket.optSet(socket, Socket.APR_SO_LINGER, socketProperties.getSoLingerTime());
             if (socketProperties.getTcpNoDelay())
                 Socket.optSet(socket, Socket.APR_TCP_NODELAY, (socketProperties.getTcpNoDelay() ? 1 : 0));
-            if (socketProperties.getSoTimeout() > 0)
-                Socket.timeoutSet(socket, socketProperties.getSoTimeout() * 1000);
+            Socket.timeoutSet(socket, socketProperties.getSoTimeout() * 1000);
 
             // 2: SSL handshake
             step = 2;
@@ -1097,14 +1098,20 @@ public class AprEndpoint extends AbstractEndpoint {
      */
     public class Poller extends Thread {
 
-        protected long serverPollset = 0;
-        protected long pool = 0;
-        protected long[] desc;
+        // Need two pollsets since the socketTimeout and the keep-alive timeout
+        // can have different values.
+        private long connectionPollset = 0;
+        private long keepAlivePollset = 0;
+        private long pool = 0;
+        private long[] desc;
 
-        protected long[] addS;
-        protected volatile int addCount = 0;
+        private long[] addSocket;
+        private boolean[] addSocketKeepAlive;
+        
+        private volatile int addCount = 0;
 
-        protected boolean comet = true;
+        private boolean comet = true;
+        private boolean separateKeepAlive = false;
 
         protected volatile int keepAliveCount = 0;
         public int getKeepAliveCount() { return keepAliveCount; }
@@ -1114,28 +1121,41 @@ public class AprEndpoint extends AbstractEndpoint {
         }
 
         /**
-         * Create the poller. With some versions of APR, the maximum poller size will
-         * be 62 (recompiling APR is necessary to remove this limitation).
+         * Create the poller. With some versions of APR, the maximum poller size
+         * will be 62 (recompiling APR is necessary to remove this limitation).
          */
         protected void init() {
             pool = Pool.create(serverSockPool);
             int size = getMaxConnections() / pollerThreadCount;
-            int timeout = getKeepAliveTimeout();
-            if (timeout <= 0) {
-                timeout = socketProperties.getSoTimeout();
+            int keepAliveTimeout = getKeepAliveTimeout();
+            int socketTimeout = socketProperties.getSoTimeout();
+            if (keepAliveTimeout != socketTimeout && !comet) {
+                separateKeepAlive = true;
+            }
+            connectionPollset = allocatePoller(size, pool, socketTimeout);
+            if (separateKeepAlive) {
+                keepAlivePollset = allocatePoller(size, pool, keepAliveTimeout);
             }
-            serverPollset = allocatePoller(size, pool, timeout);
-            if (serverPollset == 0 && size > 1024) {
+            if (connectionPollset == 0 && size > 1024) {
                 size = 1024;
-                serverPollset = allocatePoller(size, pool, timeout);
+                connectionPollset = allocatePoller(size, pool, socketTimeout);
+                if (separateKeepAlive) {
+                    keepAlivePollset =
+                        allocatePoller(size, pool, keepAliveTimeout);
+                }
             }
-            if (serverPollset == 0) {
+            if (connectionPollset == 0) {
                 size = 62;
-                serverPollset = allocatePoller(size, pool, timeout);
+                connectionPollset = allocatePoller(size, pool, socketTimeout);
+                if (separateKeepAlive) {
+                    keepAlivePollset =
+                        allocatePoller(size, pool, keepAliveTimeout);
+                }
             }
             desc = new long[size * 2];
             keepAliveCount = 0;
-            addS = new long[size];
+            addSocket = new long[size];
+            addSocketKeepAlive = new boolean[size];
             addCount = 0;
         }
 
@@ -1147,21 +1167,15 @@ public class AprEndpoint extends AbstractEndpoint {
             // Close all sockets in the add queue
             for (int i = 0; i < addCount; i++) {
                 if (comet) {
-                    processSocket(addS[i], SocketStatus.STOP);
+                    processSocket(addSocket[i], SocketStatus.STOP);
                 } else {
-                    destroySocket(addS[i]);
+                    destroySocket(addSocket[i]);
                 }
             }
-            // Close all sockets still in the poller
-            int rv = Poll.pollset(serverPollset, desc);
-            if (rv > 0) {
-                for (int n = 0; n < rv; n++) {
-                    if (comet) {
-                        processSocket(desc[n*2+1], SocketStatus.STOP);
-                    } else {
-                        destroySocket(desc[n*2+1]);
-                    }
-                }
+            // Close all sockets still in the pollers
+            closePollset(connectionPollset);
+            if (separateKeepAlive) {
+                closePollset(keepAlivePollset);
             }
             Pool.destroy(pool);
             keepAliveCount = 0;
@@ -1176,6 +1190,19 @@ public class AprEndpoint extends AbstractEndpoint {
             }
         }
 
+        private void closePollset(long pollset) {
+            int rv = Poll.pollset(pollset, desc);
+            if (rv > 0) {
+                for (int n = 0; n < rv; n++) {
+                    if (comet) {
+                        processSocket(desc[n*2+1], SocketStatus.STOP);
+                    } else {
+                        destroySocket(desc[n*2+1]);
+                    }
+                }
+            }
+        }
+
         /**
          * Add specified socket and associated pool to the poller. The socket will
          * be added to a temporary array, and polled first after a maximum amount
@@ -1184,11 +1211,11 @@ public class AprEndpoint extends AbstractEndpoint {
          *
          * @param socket to add to the poller
          */
-        public void add(long socket) {
+        public void add(long socket, boolean keepAlive) {
             synchronized (this) {
                 // Add socket to the list. Newly added sockets will wait
                 // at most for pollTime before being polled
-                if (addCount >= addS.length) {
+                if (addCount >= addSocket.length) {
                     // Can't do anything: close the socket right away
                     if (comet) {
                         processSocket(socket, SocketStatus.ERROR);
@@ -1197,7 +1224,8 @@ public class AprEndpoint extends AbstractEndpoint {
                     }
                     return;
                 }
-                addS[addCount] = socket;
+                addSocket[addCount] = socket;
+                addSocketKeepAlive[addCount] = keepAlive;
                 addCount++;
                 this.notify();
             }
@@ -1249,16 +1277,22 @@ public class AprEndpoint extends AbstractEndpoint {
                             int successCount = 0;
                             try {
                                 for (int i = (addCount - 1); i >= 0; i--) {
-                                    int rv = Poll.add
-                                        (serverPollset, addS[i], Poll.APR_POLLIN);
+                                    int rv;
+                                    if (separateKeepAlive && addSocketKeepAlive[i]) {
+                                        rv = Poll.add(keepAlivePollset,
+                                                addSocket[i], Poll.APR_POLLIN);
+                                    } else {
+                                        rv = Poll.add(connectionPollset,
+                                                addSocket[i], Poll.APR_POLLIN);
+                                    }
                                     if (rv == Status.APR_SUCCESS) {
                                         successCount++;
                                     } else {
                                         // Can't do anything: close the socket right away
                                         if (comet) {
-                                            processSocket(addS[i], SocketStatus.ERROR);
+                                            processSocket(addSocket[i], SocketStatus.ERROR);
                                         } else {
-                                            destroySocket(addS[i]);
+                                            destroySocket(addSocket[i]);
                                         }
                                     }
                                 }
@@ -1270,54 +1304,22 @@ public class AprEndpoint extends AbstractEndpoint {
                     }
 
                     maintainTime += pollTime;
-                    // Pool for the specified interval
-                    int rv = Poll.poll(serverPollset, pollTime, desc, true);
-                    if (rv > 0) {
-                        keepAliveCount -= rv;
-                        for (int n = 0; n < rv; n++) {
-                            // Check for failed sockets and hand this socket off to a worker
-                            if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
-                                    || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)
-                                    || (comet && (!processSocket(desc[n*2+1], SocketStatus.OPEN)))
-                                    || (!comet && (!processSocket(desc[n*2+1])))) {
-                                // Close socket and clear pool
-                                if (comet) {
-                                    processSocket(desc[n*2+1], SocketStatus.DISCONNECT);
-                                } else {
-                                    destroySocket(desc[n*2+1]);
-                                }
-                                continue;
-                            }
-                        }
-                    } else if (rv < 0) {
-                        int errn = -rv;
-                        /* Any non timeup or interrupted error is critical */
-                        if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) {
-                            if (errn >  Status.APR_OS_START_USERERR) {
-                                errn -=  Status.APR_OS_START_USERERR;
-                            }
-                            log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn)));
-                            // Handle poll critical failure
-                            synchronized (this) {
-                                destroy();
-                                init();
-                            }
-                            continue;
-                        }
+                    // Poll for the specified interval
+                    if (doPoll(connectionPollset)) {
+                        continue;
                     }
-                    if (socketProperties.getSoTimeout() > 0 && maintainTime > 1000000L && running) {
-                        rv = Poll.maintain(serverPollset, desc, true);
+                    if (separateKeepAlive && doPoll(keepAlivePollset)) {
+                        continue;
+                    }
+
+                    // Check timeouts (much less frequently that polling)
+                    if (maintainTime > 1000000L && running) {
                         maintainTime = 0;
-                        if (rv > 0) {
-                            keepAliveCount -= rv;
-                            for (int n = 0; n < rv; n++) {
-                                // Close socket and clear pool
-                                if (comet) {
-                                    processSocket(desc[n], SocketStatus.TIMEOUT);
-                                } else {
-                                    destroySocket(desc[n]);
-                                }
-                            }
+                        if (socketProperties.getSoTimeout() > 0) {
+                            doTimeout(connectionPollset);
+                        }
+                        if (separateKeepAlive) {
+                            doTimeout(keepAlivePollset);
                         }
                     }
                 } catch (Throwable t) {
@@ -1333,10 +1335,59 @@ public class AprEndpoint extends AbstractEndpoint {
 
         }
 
-    }
-
+        private boolean doPoll(long pollset) {
+            int rv = Poll.poll(pollset, pollTime, desc, true);
+            if (rv > 0) {
+                keepAliveCount -= rv;
+                for (int n = 0; n < rv; n++) {
+                    // Check for failed sockets and hand this socket off to a worker
+                    if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
+                            || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)
+                            || (comet && (!processSocket(desc[n*2+1], SocketStatus.OPEN)))
+                            || (!comet && (!processSocket(desc[n*2+1])))) {
+                        // Close socket and clear pool
+                        if (comet) {
+                            processSocket(desc[n*2+1], SocketStatus.DISCONNECT);
+                        } else {
+                            destroySocket(desc[n*2+1]);
+                        }
+                        return true;
+                    }
+                }
+            } else if (rv < 0) {
+                int errn = -rv;
+                /* Any non timeup or interrupted error is critical */
+                if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) {
+                    if (errn >  Status.APR_OS_START_USERERR) {
+                        errn -=  Status.APR_OS_START_USERERR;
+                    }
+                    log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn)));
+                    // Handle poll critical failure
+                    synchronized (this) {
+                        destroy();
+                        init();
+                    }
+                    return true;
+                }
+            }
+            return false;
+        }
 
-    // ----------------------------------------------------- Worker Inner Class
+        private void doTimeout(long pollset) {
+            int rv = Poll.maintain(pollset, desc, true);
+            if (rv > 0) {
+                keepAliveCount -= rv;
+                for (int n = 0; n < rv; n++) {
+                    // Close socket and clear pool
+                    if (comet) {
+                        processSocket(desc[n], SocketStatus.TIMEOUT);
+                    } else {
+                        destroySocket(desc[n]);
+                    }
+                }
+            }
+        }
+    }
 
 
     // ----------------------------------------------- SendfileData Inner Class
@@ -1622,7 +1673,7 @@ public class AprEndpoint extends AbstractEndpoint {
                                     Socket.timeoutSet(state.socket, socketProperties.getSoTimeout() * 1000);
                                     // If all done put the socket back in the poller for
                                     // processing of further requests
-                                    getPoller().add(state.socket);
+                                    getPoller().add(state.socket, true);
                                 } else {
                                     // Close the socket since this is
                                     // the end of not keep-alive request.
@@ -1713,7 +1764,7 @@ public class AprEndpoint extends AbstractEndpoint {
             synchronized (socket) {
                 if (!deferAccept) {
                     if (setSocketOptions(socket.getSocket().longValue())) {
-                        getPoller().add(socket.getSocket().longValue());
+                        getPoller().add(socket.getSocket().longValue(), false);
                     } else {
                         // Close socket and pool
                         destroySocket(socket.getSocket().longValue());
diff --git a/java/org/apache/tomcat/util/net/JIoEndpoint.java b/java/org/apache/tomcat/util/net/JIoEndpoint.java
index 3ef6a0c..fc3bbef 100644
--- a/java/org/apache/tomcat/util/net/JIoEndpoint.java
+++ b/java/org/apache/tomcat/util/net/JIoEndpoint.java
@@ -108,6 +108,8 @@ public class JIoEndpoint extends AbstractEndpoint {
     public boolean getUseCometTimeout() { return false; } // Not supported
     @Override
     public boolean getDeferAccept() { return false; } // Not supported
+    @Override
+    public boolean getUsePolling() { return false; } // Not supported
 
 
     // ------------------------------------------------ Handler Inner Interface
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
index cb628df..6138ba6 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -332,6 +332,8 @@ public class NioEndpoint extends AbstractEndpoint {
     public boolean getUseComet() { return useComet; }
     @Override
     public boolean getUseCometTimeout() { return getUseComet(); }
+    @Override
+    public boolean getUsePolling() { return true; } // Always supported
 
 
     /**
@@ -968,13 +970,19 @@ public class NioEndpoint extends AbstractEndpoint {
             else r.reset(socket,null,interestOps);
             addEvent(r);
         }
-        
+
+        /**
+         * Processes events in the event queue of the Poller.
+         * 
+         * @return <code>true</code> if some events were processed,
+         *   <code>false</code> if queue was empty
+         */
         public boolean events() {
             boolean result = false;
 
             Runnable r = null;
-            result = (events.size() > 0);
             while ( (r = events.poll()) != null ) {
+                result = true;
                 try {
                     r.run();
                     if ( r instanceof PollerEvent ) {
@@ -1079,13 +1087,11 @@ public class NioEndpoint extends AbstractEndpoint {
                     }
                     try {
                         if ( !close ) {
-                            if (wakeupCounter.get()>0) {
+                            if (wakeupCounter.getAndSet(-1) > 0) {
                                 //if we are here, means we have other stuff to do
                                 //do a non blocking select
                                 keyCount = selector.selectNow();
-                            }else {
-                                keyCount = selector.keys().size();
-                                wakeupCounter.set(-1);
+                            } else {
                                 keyCount = selector.select(selectorTimeout);
                             }
                             wakeupCounter.set(0);
@@ -1160,7 +1166,7 @@ public class NioEndpoint extends AbstractEndpoint {
             boolean result = true;
             try {
                 if ( close ) {
-                    cancelledKey(sk, SocketStatus.STOP, false);
+                    cancelledKey(sk, SocketStatus.STOP, attachment.comet);
                 } else if ( sk.isValid() && attachment != null ) {
                     attachment.access();//make sure we don't time out valid sockets
                     sk.attach(attachment);//cant remember why this is here
@@ -1338,7 +1344,7 @@ public class NioEndpoint extends AbstractEndpoint {
                               (ka.interestOps()&SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
                         //only timeout sockets that we are waiting for a read from
                         long delta = now - ka.getLastAccess();
-                        long timeout = (ka.getTimeout()==-1)?((long) socketProperties.getSoTimeout()):(ka.getTimeout());
+                        long timeout = ka.getTimeout();
                         boolean isTimedout = timeout > 0 && delta > timeout;
                         if ( close ) {
                             key.interestOps(0); 
@@ -1348,7 +1354,7 @@ public class NioEndpoint extends AbstractEndpoint {
                             key.interestOps(0); 
                             ka.interestOps(0); //avoid duplicate timeout calls
                             cancelledKey(key, SocketStatus.TIMEOUT,true);
-                        } else {
+                        } else if (timeout > -1) {
                             long nextTime = now+(timeout-delta);
                             nextExpiration = (nextTime < nextExpiration)?nextTime:nextExpiration;
                         }
diff --git a/java/org/apache/tomcat/util/net/SSLSupport.java b/java/org/apache/tomcat/util/net/SSLSupport.java
index e569ca5..f28db68 100644
--- a/java/org/apache/tomcat/util/net/SSLSupport.java
+++ b/java/org/apache/tomcat/util/net/SSLSupport.java
@@ -45,7 +45,7 @@ public interface SSLSupport {
      * This one is a Tomcat extension to the Servlet spec.
      */
     public static final String SESSION_ID_KEY =
-            "javax.servlet.request.ssl_session";
+            "javax.servlet.request.ssl_session_id";
 
     /**
      * The request attribute key for the session manager.
diff --git a/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java b/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java
index a06a42a..bebacba 100644
--- a/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java
+++ b/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java
@@ -22,6 +22,8 @@ import java.security.Principal;
 import java.security.PrivateKey;
 import java.security.cert.X509Certificate;
 
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
 import javax.net.ssl.X509KeyManager;
 
 /**
@@ -31,7 +33,7 @@ import javax.net.ssl.X509KeyManager;
  *
  * @author Jan Luehe
  */
-public final class JSSEKeyManager implements X509KeyManager {
+public final class JSSEKeyManager extends X509ExtendedKeyManager {
 
     private X509KeyManager delegate;
     private String serverKeyAlias;
@@ -44,6 +46,7 @@ public final class JSSEKeyManager implements X509KeyManager {
      * supporting certificate chain
      */
     public JSSEKeyManager(X509KeyManager mgr, String serverKeyAlias) {
+        super();
         this.delegate = mgr;
         this.serverKeyAlias = serverKeyAlias;
     }
@@ -74,12 +77,9 @@ public final class JSSEKeyManager implements X509KeyManager {
      * Returns this key manager's server key alias that was provided in the
      * constructor.
      *
-     * @param keyType The key algorithm type name (ignored)
-     * @param issuers The list of acceptable CA issuer subject names, or null
-     * if it does not matter which issuers are used (ignored)
-     * @param socket The socket to be used for this connection. This parameter
-     * can be null, in which case this method will return the most generic
-     * alias to use (ignored)
+     * @param keyType Ignored
+     * @param issuers Ignored
+     * @param socket Ignored
      *
      * @return Alias name for the desired key
      */
@@ -148,4 +148,40 @@ public final class JSSEKeyManager implements X509KeyManager {
     public PrivateKey getPrivateKey(String alias) {
         return delegate.getPrivateKey(alias);
     }
+
+    /**
+     * Choose an alias to authenticate the client side of a secure socket,
+     * given the public key type and the list of certificate issuer authorities
+     * recognized by the peer (if any).
+     *
+     * @param keyType The key algorithm type name(s), ordered with the
+     * most-preferred key type first
+     * @param issuers The list of acceptable CA issuer subject names, or null
+     * if it does not matter which issuers are used
+     * @param engine Ignored
+     *
+     * @return The alias name for the desired key, or null if there are no
+     * matches
+     */
+    @Override
+    public String chooseEngineClientAlias(String[] keyType, Principal[] issuers,
+            SSLEngine engine) {
+        return delegate.chooseClientAlias(keyType, issuers, null);
+    }
+
+    /**
+     * Returns this key manager's server key alias that was provided in the
+     * constructor.
+     *
+     * @param keyType Ignored
+     * @param issuers Ignored
+     * @param engine Ignored
+     *
+     * @return Alias name for the desired key
+     */
+    @Override
+    public String chooseEngineServerAlias(String keyType, Principal[] issuers,
+            SSLEngine engine) {
+        return serverKeyAlias;
+    }
 }
diff --git a/java/org/apache/tomcat/util/net/jsse/JSSESupport.java b/java/org/apache/tomcat/util/net/jsse/JSSESupport.java
index 757b7b8..f0fcfd9 100644
--- a/java/org/apache/tomcat/util/net/jsse/JSSESupport.java
+++ b/java/org/apache/tomcat/util/net/jsse/JSSESupport.java
@@ -35,6 +35,7 @@ import javax.security.cert.X509Certificate;
 
 import org.apache.tomcat.util.net.SSLSessionManager;
 import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.res.StringManager;
 
 /** JSSESupport
 
@@ -56,6 +57,9 @@ class JSSESupport implements SSLSupport, SSLSessionManager {
     private static final org.apache.juli.logging.Log log =
         org.apache.juli.logging.LogFactory.getLog(JSSESupport.class);
     
+    private static final StringManager sm =
+        StringManager.getManager("org.apache.tomcat.util.net.jsse.res");
+
     private static final Map<SSLSession,Integer> keySizeCache =
         new WeakHashMap<SSLSession, Integer>();
 
@@ -94,7 +98,7 @@ class JSSESupport implements SSLSupport, SSLSessionManager {
         try {
             certs = session.getPeerCertificates();
         } catch( Throwable t ) {
-            log.debug("Error getting client certs",t);
+            log.debug(sm.getString("jsseSupport.clientCertError"), t);
             return null;
         }
         if( certs==null ) return null;
@@ -115,7 +119,8 @@ class JSSESupport implements SSLSupport, SSLSessionManager {
                     x509Certs[i] = (java.security.cert.X509Certificate)
                             cf.generateCertificate(stream);
                 } catch(Exception ex) { 
-                    log.info("Error translating cert " + certs[i], ex);
+                    log.info(sm.getString(
+                            "jseeSupport.certTranslationError", certs[i]), ex);
                     return null;
                 }
             }
@@ -153,7 +158,7 @@ class JSSESupport implements SSLSupport, SSLSessionManager {
 
     protected void handShake() throws IOException {
         if( ssl.getWantClientAuth() ) {
-            log.debug("No client cert sent for want");
+            log.debug(sm.getString("jsseSupport.noCertWant"));
         } else {
             ssl.setNeedClientAuth(true);
         }
@@ -161,7 +166,7 @@ class JSSESupport implements SSLSupport, SSLSessionManager {
         if (ssl.getEnabledCipherSuites().length == 0) {
             // Handshake is never going to be successful.
             // Assume this is because handshakes are disabled
-            log.warn("SSL server initiated renegotiation is disabled, closing connection");
+            log.warn(sm.getString("jsseSupport.serverRenegDisabled"));
             session.invalidate();
             ssl.close();
             return;
@@ -170,7 +175,7 @@ class JSSESupport implements SSLSupport, SSLSessionManager {
         InputStream in = ssl.getInputStream();
         int oldTimeout = ssl.getSoTimeout();
         ssl.setSoTimeout(1000);
-        byte[] b = new byte[0];
+        byte[] b = new byte[1];
         listener.reset();
         ssl.startHandshake();
         int maxTries = 60; // 60 * 1000 = example 1 minute time out
@@ -178,9 +183,16 @@ class JSSESupport implements SSLSupport, SSLSessionManager {
             if (log.isTraceEnabled())
                 log.trace("Reading for try #" + i);
             try {
-                in.read(b);
+                int read = in.read(b);
+                if (read > 0) {
+                    // Shouldn't happen as all input should have been swallowed
+                    // before trying to do the handshake. If it does, something
+                    // went wrong so lets bomb out now.
+                    throw new SSLException(
+                            sm.getString("jsseSupport.unexpectedData"));
+                }
             } catch(SSLException sslex) {
-                log.info("SSL Error getting client Certs",sslex);
+                log.info(sm.getString("jsseSupport.clientCertError"), sslex);
                 throw sslex;
             } catch (IOException e) {
                 // ignore - presumably the timeout
@@ -221,7 +233,7 @@ class JSSESupport implements SSLSupport, SSLSessionManager {
                     break;
                 }
             }
-            keySize = new Integer(size);
+            keySize = Integer.valueOf(size);
             synchronized(keySizeCache) {
                 keySizeCache.put(session, keySize);
             }
diff --git a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
index 5e8ce34..a01e0c9 100644
--- a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
@@ -17,4 +17,9 @@ jsse.alias_no_key_entry=Alias name {0} does not identify a key entry
 jsse.keystore_load_failed=Failed to load keystore type {0} with path {1} due to {2}
 jsse.invalid_ssl_conf=SSL configuration is invalid due to {0}
 jsse.invalid_truststore_password=The provided trust store password could not be used to unlock and/or validate the trust store. Retrying to access the trust store with a null password which will skip validation.
-jsse.invalidTrustManagerClassName=The trustManagerClassName provided [{0}] does not implement javax.net.ssl.TrustManager 
\ No newline at end of file
+jsse.invalidTrustManagerClassName=The trustManagerClassName provided [{0}] does not implement javax.net.ssl.TrustManager
+jsseSupport.clientCertError=Error trying to obtain a certificate from the client
+jseeSupport.certTranslationError=Error translating certificate [{0}]
+jsseSupport.noCertWant=No client certificate sent for want
+jsseSupport.serverRenegDisabled=SSL server initiated renegotiation is disabled, closing connection
+jsseSupport.unexpectedData=Unexpected data read from input stream
\ No newline at end of file
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
index b2a7644..232a829 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
@@ -394,22 +394,6 @@ public class ConnectionPool {
      */
     protected void init(PoolConfiguration properties) throws SQLException {
         poolProperties = properties;
-        //make space for 10 extra in case we flow over a bit
-        busy = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),false);
-        //busy = new FairBlockingQueue<PooledConnection>();
-        //make space for 10 extra in case we flow over a bit
-        if (properties.isFairQueue()) {
-            idle = new FairBlockingQueue<PooledConnection>();
-            //idle = new MultiLockFairBlockingQueue<PooledConnection>();
-        } else {
-            idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),properties.isFairQueue());
-        }
-
-        //if the evictor thread is supposed to run, start it now
-        if (properties.isPoolSweeperEnabled()) {
-            poolCleaner = new PoolCleaner("[Pool-Cleaner]:" + properties.getName(), this, properties.getTimeBetweenEvictionRunsMillis());
-            poolCleaner.start();
-        } //end if
 
         //make sure the pool is properly configured
         if (properties.getMaxActive()<1) {
@@ -432,6 +416,23 @@ public class ConnectionPool {
             log.warn("maxIdle is smaller than minIdle, setting maxIdle to: "+properties.getMinIdle());
             properties.setMaxIdle(properties.getMinIdle());
         }
+
+        //make space for 10 extra in case we flow over a bit
+        busy = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),false);
+        //busy = new FairBlockingQueue<PooledConnection>();
+        //make space for 10 extra in case we flow over a bit
+        if (properties.isFairQueue()) {
+            idle = new FairBlockingQueue<PooledConnection>();
+            //idle = new MultiLockFairBlockingQueue<PooledConnection>();
+        } else {
+            idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),properties.isFairQueue());
+        }
+
+        //if the evictor thread is supposed to run, start it now
+        if (properties.isPoolSweeperEnabled()) {
+            poolCleaner = new PoolCleaner("[Pool-Cleaner]:" + properties.getName(), this, properties.getTimeBetweenEvictionRunsMillis());
+            poolCleaner.start();
+        } //end if
         
         //create JMX MBean
         if (this.getPoolProperties().isJmxEnabled()) createMBean();
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
index 32e5a4e..1228b1d 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
@@ -142,6 +142,7 @@ public class DataSourceFactory implements ObjectFactory {
         PROP_URL,
         PROP_USERNAME,
         PROP_VALIDATIONQUERY,
+        PROP_VALIDATOR_CLASS_NAME,
         PROP_VALIDATIONINTERVAL,
         PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
         PROP_REMOVEABANDONED,
@@ -161,6 +162,7 @@ public class DataSourceFactory implements ObjectFactory {
         PROP_USE_CON_LOCK,
         PROP_DATASOURCE,
         PROP_DATASOURCE_JNDI,
+        PROP_SUSPECT_TIMEOUT,
         PROP_ALTERNATE_USERNAME_ALLOWED
     };
 
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
index 4ab72fd..d8f3503 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
@@ -309,7 +309,7 @@ public class PooledConnection {
      * @param finalize if set to true, a call to {@link ConnectionPool#finalize(PooledConnection)} is called.
      */
     private void disconnect(boolean finalize) {
-        if (isDiscarded()) {
+        if (isDiscarded() && connection == null) {
             return;
         }
         setDiscarded(true);
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java
index 76d17e3..1c36d7c 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java
@@ -94,7 +94,7 @@ public class ProxyConnection extends JdbcInterceptor {
             return Boolean.valueOf(isClosed());
         }
         if (compare(CLOSE_VAL,method)) {
-            if (isClosed()) return null; //noop for already closed.
+            if (connection==null) return null; //noop for already closed.
             PooledConnection poolc = this.connection;
             this.connection = null;
             pool.returnConnection(poolc);
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java
index 922205e..c48474c 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementDecoratorInterceptor.java
@@ -127,7 +127,7 @@ public class StatementDecoratorInterceptor extends AbstractCreateStatementInterc
         result = constructor.newInstance(new Object[] { statementProxy });
         statementProxy.setActualProxy(result);
         statementProxy.setConnection(proxy);
-        statementProxy.setConnection(constructor);
+        statementProxy.setConstructor(constructor);
         return result;
     }
 
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java
index a86e6e9..2e1f620 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AbandonPercentageTest.java
@@ -108,7 +108,7 @@ public class AbandonPercentageTest extends DefaultTestCase {
         assertEquals("Number of connections active/busy should be "+con.length,con.length,datasource.getPool().getActive());
         this.datasource.getPoolProperties().setRemoveAbandonedTimeout(1);
         Thread.sleep(2500);
-        this.assertTrue("Number of connections should be less than 50.", (datasource.getPool().getActive()<50));
+        assertTrue("Number of connections should be less than 50.", (datasource.getPool().getActive()<50));
         this.datasource.getPoolProperties().setAbandonWhenPercentageFull(0);
         Thread.sleep(2500);
         assertEquals("Number of connections active/busy should be "+0,0,datasource.getPool().getActive());
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AlternateUsernameTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AlternateUsernameTest.java
index 0ea3e2a..c6915b7 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AlternateUsernameTest.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/AlternateUsernameTest.java
@@ -20,7 +20,6 @@ package org.apache.tomcat.jdbc.test;
 import java.sql.SQLException;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Random;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -107,6 +106,7 @@ public class AlternateUsernameTest extends DefaultTestCase {
             useuser = user!=null;
         }
         
+        @Override
         public TestResult call() {
             TestResult test = new TestResult();
             PooledConnection pcon = null;
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Async0IdleTestBug50477.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Async0IdleTestBug50477.java
index cfc9210..3b65667 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Async0IdleTestBug50477.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/Async0IdleTestBug50477.java
@@ -40,7 +40,7 @@ public class Async0IdleTestBug50477 extends DefaultTestCase {
         this.datasource.getPoolProperties().setInitialSize(0);
         try {
             Future<Connection> cf = ((DataSourceProxy)datasource).getConnectionAsync();
-            Connection con  = cf.get(5, TimeUnit.SECONDS);
+            cf.get(5, TimeUnit.SECONDS);
         }finally {
             tearDown();
         }
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/BorrowWaitTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/BorrowWaitTest.java
index 1244140..3775ef8 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/BorrowWaitTest.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/BorrowWaitTest.java
@@ -39,7 +39,9 @@ public class BorrowWaitTest extends DefaultTestCase {
         }catch (SQLException x) {
             long delta = System.currentTimeMillis();
             boolean inrange = Math.abs(wait-delta) < 1000;
-            assertTrue("Connection should have been acquired within +/- 1 second.",true);
+            assertTrue(
+                    "Connection should have been acquired within +/- 1 second.",
+                    inrange);
         }
         con.close();
     }
@@ -49,6 +51,7 @@ public class BorrowWaitTest extends DefaultTestCase {
             System.err.println("testWaitTimeInfinite() test is disabled.");
             return;//this would lock up the test suite
         }
+        /*
         int wait = -1;
         this.init();
         this.datasource.setMaxActive(1);
@@ -64,6 +67,7 @@ public class BorrowWaitTest extends DefaultTestCase {
             assertTrue("Connection should have been acquired within +/- 1 second.",true);
         }
         con.close();
+        */
     }
 
 
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/ConnectCountTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/ConnectCountTest.java
index 339e1aa..bcf4ad8 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/ConnectCountTest.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/ConnectCountTest.java
@@ -38,8 +38,8 @@ public class ConnectCountTest extends DefaultTestCase {
     }
     
     protected boolean run = true;
-    protected long sleep = Long.getLong("sleep", 10);
-    protected long complete = Long.getLong("complete",20000);
+    protected long sleep = Long.getLong("sleep", 10).longValue();
+    protected long complete = Long.getLong("complete",20000).longValue();
     protected boolean printthread = Boolean.getBoolean("printthread");
     CountDownLatch latch = null;
 
@@ -67,8 +67,7 @@ public class ConnectCountTest extends DefaultTestCase {
 
     protected void printThreadResults(TestThread[] threads, String name, int active, int expected) {
         long minfetch = Long.MAX_VALUE, maxfetch = Long.MIN_VALUE, totalfetch = 0;
-        long maxwait = 0, minwait = Long.MAX_VALUE, averagewait = 0, totalwait = 0;
-        float avgfetch = 0;
+        long maxwait = 0, minwait = Long.MAX_VALUE, totalwait = 0;
         for (int i=0; i<threads.length; i++) {
             TestThread t = threads[i];
             totalfetch += t.nroffetch;
@@ -78,11 +77,11 @@ public class ConnectCountTest extends DefaultTestCase {
             minfetch = Math.min(minfetch, t.nroffetch);
             maxfetch = Math.max(maxfetch, t.nroffetch);
             if (ConnectCountTest.this.printthread)
-                System.out.println(t.getName()+" : Nr-of-fetch:"+t.nroffetch+ " Max fetch Time:"+(((float)t.maxwait)/1000000f)+"ms. :Max close time:"+(((float)t.cmax)/1000000f)+"ms.");
+                System.out.println(t.getName()+" : Nr-of-fetch:"+t.nroffetch+ " Max fetch Time:"+t.maxwait/1000000f+"ms. :Max close time:"+t.cmax/1000000f+"ms.");
         }
         System.out.println("["+name+"] Max fetch:"+(maxfetch)+" Min fetch:"+(minfetch)+" Average fetch:"+
                            (((float)totalfetch))/(float)threads.length);
-        System.out.println("["+name+"] Max wait:"+(((float)maxwait)/1000000f)+"ms. Min wait:"+(((float)minwait)/1000000f)+"ms. Average wait:"+(((((float)totalwait))/(float)totalfetch)/1000000f)+" ms.");
+        System.out.println("["+name+"] Max wait:"+maxwait/1000000f+"ms. Min wait:"+minwait/1000000f+"ms. Average wait:"+(((((float)totalwait))/(float)totalfetch)/1000000f)+" ms.");
         System.out.println("["+name+"] Max active:"+active+" Expected Active:"+expected);
         
         
@@ -112,6 +111,7 @@ public class ConnectCountTest extends DefaultTestCase {
         this.run = false;
         long delta = System.currentTimeMillis() - start;
         printThreadResults(threads,"testDBCPThreads20Connections10",Driver.connectCount.get(),10);
+        System.out.println("Test completed in: " + delta + "ms.");
         tearDown();
     }
 
@@ -139,6 +139,7 @@ public class ConnectCountTest extends DefaultTestCase {
         this.run = false;
         long delta = System.currentTimeMillis() - start;
         printThreadResults(threads,"testPoolThreads20Connections10",Driver.connectCount.get(),10);
+        System.out.println("Test completed in: " + delta + "ms.");
         tearDown();
 
     }
@@ -168,6 +169,7 @@ public class ConnectCountTest extends DefaultTestCase {
         this.run = false;
         long delta = System.currentTimeMillis() - start;
         printThreadResults(threads,"testPoolThreads20Connections10Fair",Driver.connectCount.get(),10);
+        System.out.println("Test completed in: " + delta + "ms.");
         tearDown();
     }
  
@@ -198,6 +200,7 @@ public class ConnectCountTest extends DefaultTestCase {
         this.run = false;
         long delta = System.currentTimeMillis() - start;
         printThreadResults(threads,"testPoolThreads20Connections10FairAsync",Driver.connectCount.get(),10);
+        System.out.println("Test completed in: " + delta + "ms.");
         tearDown();
     }
     
@@ -286,13 +289,13 @@ public class ConnectCountTest extends DefaultTestCase {
             }
             if (System.getProperty("print-thread-stats")!=null) {
                 System.out.println("["+getName()+"] "+
-                    "\n\tMax time to retrieve connection:"+(((float)maxwait)/1000f/1000f)+" ms."+
-                    "\n\tTotal time to retrieve connection:"+(((float)totalwait)/1000f/1000f)+" ms."+
-                    "\n\tAverage time to retrieve connection:"+(((float)totalwait)/1000f/1000f)/(float)nroffetch+" ms."+
-                    "\n\tMax time to close connection:"+(((float)cmax)/1000f/1000f)+" ms."+
-                    "\n\tTotal time to close connection:"+(((float)totalcmax)/1000f/1000f)+" ms."+
-                    "\n\tAverage time to close connection:"+(((float)totalcmax)/1000f/1000f)/(float)nroffetch+" ms."+
-                    "\n\tRun time:"+(((float)totalruntime)/1000f/1000f)+" ms."+
+                    "\n\tMax time to retrieve connection:"+maxwait/1000000f+" ms."+
+                    "\n\tTotal time to retrieve connection:"+totalwait/1000000f+" ms."+
+                    "\n\tAverage time to retrieve connection:"+totalwait/1000000f/nroffetch+" ms."+
+                    "\n\tMax time to close connection:"+cmax/1000000f+" ms."+
+                    "\n\tTotal time to close connection:"+totalcmax/1000000f+" ms."+
+                    "\n\tAverage time to close connection:"+totalcmax/1000000f/nroffetch+" ms."+
+                    "\n\tRun time:"+totalruntime/1000000f+" ms."+
                     "\n\tNr of fetch:"+nroffetch);
             }
         }
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/DefaultProperties.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/DefaultProperties.java
index 235b555..4cd25b4 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/DefaultProperties.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/DefaultProperties.java
@@ -45,8 +45,8 @@ public class DefaultProperties extends PoolProperties {
         username = System.getProperty("username","root");
         
         validationQuery = System.getProperty("validationQuery","SELECT 1");
-        defaultAutoCommit = true;
-        defaultReadOnly = false;
+        defaultAutoCommit = Boolean.TRUE;
+        defaultReadOnly = Boolean.FALSE;
         defaultTransactionIsolation = DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION;
         connectionProperties = null;
         defaultCatalog = null;
@@ -67,7 +67,7 @@ public class DefaultProperties extends PoolProperties {
         logAbandoned = true;
         validationInterval = 0; //always validate
         initSQL = null;
-        testOnConnect = false;;
+        testOnConnect = false;
         dbProperties.setProperty("user",username);
         dbProperties.setProperty("password",password);
     }
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/DefaultTestCase.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/DefaultTestCase.java
index 401c380..9b45e42 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/DefaultTestCase.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/DefaultTestCase.java
@@ -236,6 +236,8 @@ public class DefaultTestCase extends TestCase {
         PROP_REMOVEABANDONED,
         PROP_REMOVEABANDONEDTIMEOUT,
         PROP_LOGABANDONED,
+        PROP_POOLPREPAREDSTATEMENTS,
+        PROP_MAXOPENPREPAREDSTATEMENTS,
         PROP_CONNECTIONPROPERTIES
     };
 
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/FairnessTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/FairnessTest.java
index b296eee..a5fe9fa 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/FairnessTest.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/FairnessTest.java
@@ -37,14 +37,13 @@ public class FairnessTest extends DefaultTestCase {
     }
     
     protected boolean run = true;
-    protected long sleep = Long.getLong("sleep", 10);
-    protected long complete = Long.getLong("complete",20000);
+    protected long sleep = Long.getLong("sleep", 10).longValue();
+    protected long complete = Long.getLong("complete",20000).longValue();
     protected boolean printthread = Boolean.getBoolean("printthread");
     CountDownLatch latch = null;
     protected void printThreadResults(TestThread[] threads, String name, int active, int expected) {
         long minfetch = Long.MAX_VALUE, maxfetch = Long.MIN_VALUE, totalfetch = 0;
-        long maxwait = 0, minwait = Long.MAX_VALUE, averagewait = 0, totalwait = 0;
-        float avgfetch = 0;
+        long maxwait = 0, minwait = Long.MAX_VALUE, totalwait = 0;
         for (int i=0; i<threads.length; i++) {
             TestThread t = threads[i];
             totalfetch += t.nroffetch;
@@ -54,11 +53,11 @@ public class FairnessTest extends DefaultTestCase {
             minfetch = Math.min(minfetch, t.nroffetch);
             maxfetch = Math.max(maxfetch, t.nroffetch);
             if (FairnessTest.this.printthread)
-                System.out.println(t.getName()+" : Nr-of-fetch:"+t.nroffetch+ " Max fetch Time:"+(((float)t.maxwait)/1000000f)+"ms. :Max close time:"+(((float)t.cmax)/1000000f)+"ms.");
+                System.out.println(t.getName()+" : Nr-of-fetch:"+t.nroffetch+ " Max fetch Time:"+t.maxwait/1000000f+"ms. :Max close time:"+t.cmax/1000000f+"ms.");
         }
         System.out.println("["+name+"] Max fetch:"+(maxfetch)+" Min fetch:"+(minfetch)+" Average fetch:"+
                            (((float)totalfetch))/(float)threads.length);
-        System.out.println("["+name+"] Max wait:"+(((float)maxwait)/1000000f)+"ms. Min wait:"+(((float)minwait)/1000000f)+"ms. Average wait:"+(((((float)totalwait))/(float)totalfetch)/1000000f)+" ms.");
+        System.out.println("["+name+"] Max wait:"+maxwait/1000000f+"ms. Min wait:"+minwait/1000000f+"ms. Average wait:"+(((((float)totalwait))/(float)totalfetch)/1000000f)+" ms.");
         System.out.println("["+name+"] Max active:"+active+" Expected Active:"+expected);
         
         
@@ -89,6 +88,7 @@ public class FairnessTest extends DefaultTestCase {
         this.run = false;
         long delta = System.currentTimeMillis() - start;
         printThreadResults(threads,"testDBCPThreads20Connections10",this.tDatasource.getNumActive(),10);
+        System.out.println("Test completed in: " + delta + "ms.");
         tearDown();
     }
 
@@ -118,8 +118,8 @@ public class FairnessTest extends DefaultTestCase {
         this.run = false;
         long delta = System.currentTimeMillis() - start;
         printThreadResults(threads,"testPoolThreads20Connections10",this.datasource.getSize(),10);
+        System.out.println("Test completed in: " + delta + "ms.");
         tearDown();
-
     }
 
     public void testPoolThreads20Connections10Fair() throws Exception {
@@ -148,6 +148,7 @@ public class FairnessTest extends DefaultTestCase {
         this.run = false;
         long delta = System.currentTimeMillis() - start;
         printThreadResults(threads,"testPoolThreads20Connections10Fair",this.datasource.getSize(),10);
+        System.out.println("Test completed in: " + delta + "ms.");
         tearDown();
     }
  
@@ -178,6 +179,7 @@ public class FairnessTest extends DefaultTestCase {
         this.run = false;
         long delta = System.currentTimeMillis() - start;
         printThreadResults(threads,"testPoolThreads20Connections10FairAsync",this.datasource.getSize(),10);
+        System.out.println("Test completed in: " + delta + "ms.");
         tearDown();
     }
     
@@ -268,13 +270,13 @@ public class FairnessTest extends DefaultTestCase {
             }
             if (System.getProperty("print-thread-stats")!=null) {
                 System.out.println("["+getName()+"] "+
-                    "\n\tMax time to retrieve connection:"+(((float)maxwait)/1000f/1000f)+" ms."+
-                    "\n\tTotal time to retrieve connection:"+(((float)totalwait)/1000f/1000f)+" ms."+
-                    "\n\tAverage time to retrieve connection:"+(((float)totalwait)/1000f/1000f)/(float)nroffetch+" ms."+
-                    "\n\tMax time to close connection:"+(((float)cmax)/1000f/1000f)+" ms."+
-                    "\n\tTotal time to close connection:"+(((float)totalcmax)/1000f/1000f)+" ms."+
-                    "\n\tAverage time to close connection:"+(((float)totalcmax)/1000f/1000f)/(float)nroffetch+" ms."+
-                    "\n\tRun time:"+(((float)totalruntime)/1000f/1000f)+" ms."+
+                    "\n\tMax time to retrieve connection:"+maxwait/1000000f+" ms."+
+                    "\n\tTotal time to retrieve connection:"+totalwait/1000000f+" ms."+
+                    "\n\tAverage time to retrieve connection:"+totalwait/1000000f/nroffetch+" ms."+
+                    "\n\tMax time to close connection:"+cmax/1000000f+" ms."+
+                    "\n\tTotal time to close connection:"+totalcmax/1000000f+" ms."+
+                    "\n\tAverage time to close connection:"+totalcmax/1000000f/nroffetch+" ms."+
+                    "\n\tRun time:"+totalruntime/1000000f+" ms."+
                     "\n\tNr of fetch:"+nroffetch);
             }
         }
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestConcurrency.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestConcurrency.java
index 6a22d0a..617d486 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestConcurrency.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestConcurrency.java
@@ -63,6 +63,7 @@ public class TestConcurrency extends DefaultTestCase {
         final int iter = 1000 * 10;
         final AtomicInteger loopcount = new AtomicInteger(0);
         final Runnable run = new Runnable() {
+            @Override
             public void run() {
                 try {
                     while (loopcount.incrementAndGet() < iter) {
@@ -117,6 +118,7 @@ public class TestConcurrency extends DefaultTestCase {
         final int iter = 100000 * 10;
         final AtomicInteger loopcount = new AtomicInteger(0);
         final Runnable run = new Runnable() {
+            @Override
             public void run() {
                 try {
                     while (loopcount.incrementAndGet() < iter) {
@@ -167,6 +169,7 @@ public class TestConcurrency extends DefaultTestCase {
         final int iter = 100000 * 10;
         final AtomicInteger loopcount = new AtomicInteger(0);
         final Runnable run = new Runnable() {
+            @Override
             public void run() {
                 try {
                     while (loopcount.incrementAndGet() < iter) {
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSizePreservation.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSizePreservation.java
index 183532e..89c4d7c 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSizePreservation.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSizePreservation.java
@@ -90,6 +90,7 @@ public class TestSizePreservation extends TestCase {
         final int iterations = 1000;
         final AtomicInteger loopcount = new AtomicInteger(0);
         final Runnable run = new Runnable() {
+            @Override
             public void run() {
                 try {
                     while (loopcount.incrementAndGet() < iterations) {
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java
index 33dbec6..2f24ad7 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestSlowQueryReport.java
@@ -159,14 +159,13 @@ public class TestSlowQueryReport extends DefaultTestCase {
         this.datasource.setJdbcInterceptors(SlowQueryReport.class.getName());
         Connection con = this.datasource.getConnection();
         String slowSql = "select 1 from non_existent";
-        int exceptionCount = 0;
         for (int i=0; i<count; i++) {
             Statement st = con.createStatement();
             try {
                 ResultSet rs = st.executeQuery(slowSql);
                 rs.close();
             }catch (Exception x) {
-                exceptionCount++;
+                // NO-OP
             }
             st.close();
             
@@ -186,6 +185,7 @@ public class TestSlowQueryReport extends DefaultTestCase {
     
     public class ClientListener implements NotificationListener {
         volatile int notificationCount = 0;
+        @Override
         public void handleNotification(Notification notification,
                                        Object handback) {
             notificationCount++;
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java
index d3d5740..cc32aee 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/TestStatementCache.java
@@ -33,8 +33,7 @@ public class TestStatementCache extends DefaultTestCase {
     
     @Override
     protected void tearDown() throws Exception {
-        // TODO Auto-generated method stub
-        this.interceptor = null;
+        interceptor = null;
         super.tearDown();
     }
 
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Connection.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Connection.java
index 8fc3888..c3846bf 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Connection.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Connection.java
@@ -50,187 +50,236 @@ public class Connection implements java.sql.Connection {
         return info.getProperty(PooledConnection.PROP_PASSWORD);
     }
     
+    @Override
     public void clearWarnings() throws SQLException {
     }
 
+    @Override
     public void close() throws SQLException {
         Driver.disconnectCount.incrementAndGet();
     }
 
+    @Override
     public void commit() throws SQLException {
     }
 
+    @Override
     public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
         return null;
     }
 
+    @Override
     public Blob createBlob() throws SQLException {
         return null;
     }
 
+    @Override
     public Clob createClob() throws SQLException {
         return null;
     }
 
+    @Override
     public NClob createNClob() throws SQLException {
         return null;
     }
 
+    @Override
     public SQLXML createSQLXML() throws SQLException {
         return null;
     }
 
+    @Override
     public Statement createStatement() throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
         return null;
     }
 
+    @Override
     public boolean getAutoCommit() throws SQLException {
         return false;
     }
 
+    @Override
     public String getCatalog() throws SQLException {
         return null;
     }
 
+    @Override
     public Properties getClientInfo() throws SQLException {
         return null;
     }
 
+    @Override
     public String getClientInfo(String name) throws SQLException {
         return null;
     }
 
+    @Override
     public int getHoldability() throws SQLException {
         return 0;
     }
 
+    @Override
     public DatabaseMetaData getMetaData() throws SQLException {
         return null;
     }
 
+    @Override
     public int getTransactionIsolation() throws SQLException {
         return 0;
     }
 
+    @Override
     public Map<String, Class<?>> getTypeMap() throws SQLException {
         return null;
     }
 
+    @Override
     public SQLWarning getWarnings() throws SQLException {
         return null;
     }
 
+    @Override
     public boolean isClosed() throws SQLException {
         return false;
     }
 
+    @Override
     public boolean isReadOnly() throws SQLException {
         return false;
     }
 
+    @Override
     public boolean isValid(int timeout) throws SQLException {
         return false;
     }
 
+    @Override
     public String nativeSQL(String sql) throws SQLException {
         return null;
     }
 
+    @Override
     public CallableStatement prepareCall(String sql) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public PreparedStatement prepareStatement(String sql) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
     
+    @Override
     public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
     
+    @Override
     public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
         return new org.apache.tomcat.jdbc.test.driver.Statement();
     }
 
+    @Override
     public void releaseSavepoint(Savepoint savepoint) throws SQLException {
     }
 
+    @Override
     public void rollback() throws SQLException {
     }
 
+    @Override
     public void rollback(Savepoint savepoint) throws SQLException {
     }
 
+    @Override
     public void setAutoCommit(boolean autoCommit) throws SQLException {
     }
 
+    @Override
     public void setCatalog(String catalog) throws SQLException {
     }
 
+    @Override
     public void setClientInfo(Properties properties) throws SQLClientInfoException {
     }
 
+    @Override
     public void setClientInfo(String name, String value) throws SQLClientInfoException {
     }
 
+    @Override
     public void setHoldability(int holdability) throws SQLException {
     }
 
+    @Override
     public void setReadOnly(boolean readOnly) throws SQLException {
     }
 
+    @Override
     public Savepoint setSavepoint() throws SQLException {
         return null;
     }
 
+    @Override
     public Savepoint setSavepoint(String name) throws SQLException {
         return null;
     }
 
+    @Override
     public void setTransactionIsolation(int level) throws SQLException {
     }
 
+    @Override
     public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
     }
 
+    @Override
     public boolean isWrapperFor(Class<?> iface) throws SQLException {
         return false;
     }
 
+    @Override
     public <T> T unwrap(Class<T> iface) throws SQLException {
         return null;
     }
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Driver.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Driver.java
index 0b3d8cd..52c5830 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Driver.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Driver.java
@@ -45,27 +45,33 @@ public class Driver implements java.sql.Driver {
     public Driver() {
     }
     
+    @Override
     public boolean acceptsURL(String url) throws SQLException {
         return url!=null && url.equals(Driver.url);
     }
 
+    @Override
     public Connection connect(String url, Properties info) throws SQLException {
         connectCount.addAndGet(1);
         return new org.apache.tomcat.jdbc.test.driver.Connection(info);
     }
 
+    @Override
     public int getMajorVersion() {
         return 0;
     }
 
+    @Override
     public int getMinorVersion() {
         return 0;
     }
 
+    @Override
     public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
         return null;
     }
 
+    @Override
     public boolean jdbcCompliant() {
         return false;
     }
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/ResultSet.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/ResultSet.java
index 9986c48..398c733 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/ResultSet.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/ResultSet.java
@@ -41,39 +41,50 @@ import java.util.Map;
 public class ResultSet implements java.sql.ResultSet {
     boolean hasNext = true;
     
+    @Override
     public boolean absolute(int row) throws SQLException {
         return false;
     }
 
+    @Override
     public void afterLast() throws SQLException {
     }
 
+    @Override
     public void beforeFirst() throws SQLException {
     }
 
+    @Override
     public void cancelRowUpdates() throws SQLException {
     }
 
+    @Override
     public void clearWarnings() throws SQLException {
     }
+    @Override
     public void close() throws SQLException {
     }
 
+    @Override
     public void deleteRow() throws SQLException {
     }
 
+    @Override
     public int findColumn(String columnLabel) throws SQLException {
         return 0;
     }
 
+    @Override
     public boolean first() throws SQLException {
         return hasNext;
     }
 
+    @Override
     public Array getArray(int columnIndex) throws SQLException {
         return null;
     }
 
+    @Override
     public Array getArray(String columnLabel) throws SQLException {
         return null;
     }
diff --git a/res/maven/mvn.properties.default b/res/maven/mvn.properties.default
index 360b895..0fa41b8 100644
--- a/res/maven/mvn.properties.default
+++ b/res/maven/mvn.properties.default
@@ -33,12 +33,12 @@ maven.snapshot.repo.repositoryId=apache.snapshots
 #Maven release properties for Tomcat staging
 maven.release.repo.url=scp://people.apache.org/www/tomcat.apache.org/dev/dist/m2-repository
 maven.release.repo.repositoryId=tomcat-staging
-maven.release.deploy.version=7.0.21
+maven.release.deploy.version=7.0.22
 
 #Maven release properties for the main ASF repo
 maven.asf.release.repo.url=scp://people.apache.org/www/people.apache.org/repo/m2-ibiblio-rsync-repository
 maven.asf.release.repo.repositoryId=apache.releases
-maven.asf.release.deploy.version=7.0.21
+maven.asf.release.deploy.version=7.0.22
 
 
 #Where do we load the libraries from
diff --git a/res/maven/tomcat-jdbc.pom b/res/maven/tomcat-jdbc.pom
index 100b383..5162923 100644
--- a/res/maven/tomcat-jdbc.pom
+++ b/res/maven/tomcat-jdbc.pom
@@ -24,7 +24,7 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
-      <artifactId>tomcat-jdbc</artifactId>
+      <artifactId>tomcat-juli</artifactId>
       <version>@MAVEN.DEPLOY.VERSION@</version>
       <scope>compile</scope>
     </dependency>
diff --git a/test/javax/el/TestBeanELResolverVarargsInvocation.java b/test/javax/el/TestBeanELResolverVarargsInvocation.java
new file mode 100644
index 0000000..d7abfa1
--- /dev/null
+++ b/test/javax/el/TestBeanELResolverVarargsInvocation.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package javax.el;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestBeanELResolverVarargsInvocation {
+    public static class Foo {
+
+        public String joinDelimited(String delim, String... strings) {
+            StringBuilder result = new StringBuilder();
+            if (strings != null) {
+                for (String s : strings) {
+                    if (delim != null && result.length() > 0) {
+                        result.append(delim);
+                    }
+                    result.append(s);
+                }
+            }
+            return result.toString();
+        }
+
+        public String join(String... strings) {
+            return joinDelimited(null, strings);
+        }
+    }
+
+    private Foo foo;
+    private ELContext elContext;
+    private BeanELResolver beanELResolver;
+
+    @Before
+    public void setup() {
+        foo = new Foo();
+        beanELResolver = new BeanELResolver();
+        elContext = new ELContext() {
+            private VariableMapper variableMapper = new VariableMapper() {
+                private Map<String, ValueExpression> vars =
+                    new HashMap<String, ValueExpression>();
+
+                @Override
+                public ValueExpression setVariable(String arg0,
+                        ValueExpression arg1) {
+                    return vars.put(arg0, arg1);
+                }
+
+                @Override
+                public ValueExpression resolveVariable(String arg0) {
+                    return vars.get(arg0);
+                }
+            };
+            private FunctionMapper functionMapper = new FunctionMapper() {
+
+                @Override
+                public Method resolveFunction(String arg0, String arg1) {
+                    return null;
+                }
+            };
+
+            @Override
+            public VariableMapper getVariableMapper() {
+                return variableMapper;
+            }
+
+            @Override
+            public FunctionMapper getFunctionMapper() {
+                return functionMapper;
+            }
+
+            @Override
+            public ELResolver getELResolver() {
+                return beanELResolver;
+            }
+        };
+    }
+
+    /**
+     * Tests varargs that come after an opening argument.
+     */
+    @Test
+    public void testJoinDelimited() {
+        Assert.assertEquals(foo.joinDelimited("-", "foo", "bar", "baz"),
+            beanELResolver.invoke(elContext, foo, "joinDelimited", null,
+                    new Object[] { "-", "foo", "bar", "baz" }));
+    }
+
+    /**
+     * Tests varargs that constitute a method's only parameters, as well as
+     * bogus results due to improper matching of ANY vararg method, and
+     * depending on the order in which reflected methods are encountered.
+     */
+    @Test
+    public void testJoin() {
+        Assert.assertEquals(foo.join("foo", "bar", "baz"),
+            beanELResolver.invoke(elContext, foo, "join", null,
+                    new Object[] { "foo", "bar", "baz" }));
+    }
+
+}
\ No newline at end of file
diff --git a/test/org/apache/catalina/comet/TestCometProcessor.java b/test/org/apache/catalina/comet/TestCometProcessor.java
index e369552..c6c6105 100644
--- a/test/org/apache/catalina/comet/TestCometProcessor.java
+++ b/test/org/apache/catalina/comet/TestCometProcessor.java
@@ -151,15 +151,32 @@ public class TestCometProcessor extends TomcatBaseTest {
         Thread.sleep(3000);
         
         tomcat.getConnector().stop();
+        // Allow the executor a chance to send the end event
+        Thread.sleep(100);
         tomcat.getConnector().destroy();
 
-        // Sleep for a couple of seconds to give enough time for the connector
-        // stop message to be processed
-        Thread.sleep(2000);
+        // Wait for the write thread to stop
+        int count = 0;
+        while (writeThread.isAlive() && count < 50) {
+            Thread.sleep(100);
+            count ++;
+        }
+
+        // Wait for the read thread to stop
+        while (readThread.isAlive() && count < 50) {
+            Thread.sleep(100);
+            count ++;
+        }
 
         // Write should trigger an exception once the connector stops since the
         // socket should be closed
-        assertNotNull(writeThread.getException());
+        assertNotNull("No exception in writing thread",
+                writeThread.getException());
+
+        // Termination of Read thread varies by platform and protocol
+        // In all cases, the END event should be sent.
+        assertTrue("Comet END event not received",
+                readThread.getResponse().contains("Client: END"));
     }
 
     private boolean isCometSupported() {
@@ -215,7 +232,7 @@ public class TestCometProcessor extends TomcatBaseTest {
         
         private int pingCount;
         private OutputStream os;
-        private Exception e = null;
+        private volatile Exception e = null;
 
         public PingWriterThread(int pingCount, OutputStream os) {
             this.pingCount = pingCount;
@@ -247,7 +264,6 @@ public class TestCometProcessor extends TomcatBaseTest {
 
         private InputStream is;
         private StringBuilder response = new StringBuilder();
-        private Exception e = null;
 
         public ResponseReaderThread(InputStream is) {
             this.is = is;
@@ -257,10 +273,6 @@ public class TestCometProcessor extends TomcatBaseTest {
             return response.toString();
         }
 
-        public Exception getException() {
-            return e;
-        }
-
         @Override
         public void run() {
             try {
@@ -270,7 +282,7 @@ public class TestCometProcessor extends TomcatBaseTest {
                     c = is.read();
                 }
             } catch (Exception e) {
-                this.e = e;
+                // Ignore
             }
         }
     }
diff --git a/test/org/apache/catalina/connector/TestCoyoteAdapter.java b/test/org/apache/catalina/connector/TestCoyoteAdapter.java
index 53d6c8e..8e05a00 100644
--- a/test/org/apache/catalina/connector/TestCoyoteAdapter.java
+++ b/test/org/apache/catalina/connector/TestCoyoteAdapter.java
@@ -87,6 +87,7 @@ public class TestCoyoteAdapter extends TomcatBaseTest {
         
         // Create the folder that will trigger the redirect
         File foo = new File(docBase, "foo");
+        addDeleteOnTearDown(foo);
         if (!foo.mkdirs() && !foo.isDirectory()) {
             fail("Unable to create foo directory in docBase");
         }
diff --git a/test/org/apache/catalina/connector/TestMaxConnections.java b/test/org/apache/catalina/connector/TestMaxConnections.java
index c9b45ca..5723b02 100644
--- a/test/org/apache/catalina/connector/TestMaxConnections.java
+++ b/test/org/apache/catalina/connector/TestMaxConnections.java
@@ -60,7 +60,7 @@ public class TestMaxConnections extends TomcatBaseTest {
         }
         
         assertTrue("The number of successful requests should have been 4-5, actual "+passcount,4==passcount || 5==passcount);
-        
+        System.out.println("There were [" + connectfail + "] connection failures");
     }
 
     private static class ConnectThread extends Thread {
diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java b/test/org/apache/catalina/core/TestAsyncContextImpl.java
index 66d129a..3d9b941 100644
--- a/test/org/apache/catalina/core/TestAsyncContextImpl.java
+++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java
@@ -411,6 +411,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         
         // Create the folder that will trigger the redirect
         File foo = new File(docBase, "async");
+        addDeleteOnTearDown(foo);
         if (!foo.mkdirs() && !foo.isDirectory()) {
             fail("Unable to create async directory in docBase");
         }
diff --git a/test/org/apache/catalina/core/TestDefaultInstanceManager.java b/test/org/apache/catalina/core/TestDefaultInstanceManager.java
new file mode 100644
index 0000000..e2c1bef
--- /dev/null
+++ b/test/org/apache/catalina/core/TestDefaultInstanceManager.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.core;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+
+
+public class TestDefaultInstanceManager extends TomcatBaseTest {
+
+    @Test
+    public void testClassUnloading() throws Exception {
+        
+        DefaultInstanceManager instanceManager = doClassUnloadingPrep();
+
+        // Request a JSP page (that doesn't load any tag libraries etc.)
+        // This page does use @PostConstruct to ensure that the cache does not
+        // retain strong references
+        getUrl("http://localhost:" + getPort() + "/test/annotations.jsp");
+        // Request a second JSP (again, no tag libraries etc.)
+        getUrl("http://localhost:" + getPort() + "/test/bug36923.jsp");
+        
+        // Check the number of classes in the cache
+        int count = instanceManager.getAnnotationCacheSize();
+
+        // Request a third JSP (again, no tag libraries etc.)
+        getUrl("http://localhost:" + getPort() + "/test/bug51544.jsp");
+        
+        // Force a GC to clear out unloaded class (first JSP)
+        System.gc();
+
+        // Spin a while until GC happens or we wait too long
+        int loop = 0;
+        while (loop < 10) {
+            if (instanceManager.getAnnotationCacheSize() == count) {
+                break;
+            }
+            Thread.sleep(100);
+            loop++;
+        }
+
+        // First JSP should be unloaded and replaced by third (second left
+        // alone) so no change in overall count
+        assertEquals(count, instanceManager.getAnnotationCacheSize());
+    }
+
+    private DefaultInstanceManager doClassUnloadingPrep() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        
+        // Create the context (don't use addWebapp as we want to modify the
+        // JSP Servlet settings).
+        File appDir = new File("test/webapp-3.0");
+        StandardContext ctxt = (StandardContext) tomcat.addContext(
+                null, "/test", appDir.getAbsolutePath());
+        
+        // Configure the defaults and then tweak the JSP servlet settings
+        // Note: Min value for maxLoadedJsps is 2
+        Tomcat.initWebappDefaults(ctxt);
+        Wrapper w = (Wrapper) ctxt.findChild("jsp");
+        w.addInitParameter("maxLoadedJsps", "2");
+        
+        tomcat.start();
+        
+        return (DefaultInstanceManager) ctxt.getInstanceManager();
+    }
+}
diff --git a/test/org/apache/catalina/mbeans/TestRegistration.java b/test/org/apache/catalina/mbeans/TestRegistration.java
index 893f007..7336c33 100644
--- a/test/org/apache/catalina/mbeans/TestRegistration.java
+++ b/test/org/apache/catalina/mbeans/TestRegistration.java
@@ -116,9 +116,9 @@ public class TestRegistration extends TomcatBaseTest {
 
         final Tomcat tomcat = getTomcatInstance();
         final File contextDir = new File(getTemporaryDirectory(), "webappFoo");
-        if (!contextDir.exists()) {
-            if (!contextDir.mkdir())
-                fail("Failed to create: [" + contextDir.toString() + "]");
+        addDeleteOnTearDown(contextDir);
+        if (!contextDir.mkdirs() && !contextDir.isDirectory()) {
+            fail("Failed to create: [" + contextDir.toString() + "]");
         }
         tomcat.addContext(contextName, contextDir.getAbsolutePath());
         tomcat.start();
@@ -172,9 +172,9 @@ public class TestRegistration extends TomcatBaseTest {
         tomcat.getEngine().addChild(host);
 
         final File contextDir2 = new File(getTemporaryDirectory(), "webappFoo2");
-        if (!contextDir2.exists()) {
-            if (!contextDir2.mkdir())
-                fail("Failed to create: [" + contextDir2.toString() + "]");
+        addDeleteOnTearDown(contextDir2);
+        if (!contextDir2.mkdirs() && !contextDir2.isDirectory()) {
+            fail("Failed to create: [" + contextDir2.toString() + "]");
         }
         tomcat.addContext(host, contextName + "2", contextDir2.getAbsolutePath());
         
diff --git a/test/org/apache/catalina/servlets/TestDefaultServlet.java b/test/org/apache/catalina/servlets/TestDefaultServlet.java
index 5ac2f11..d0339db 100644
--- a/test/org/apache/catalina/servlets/TestDefaultServlet.java
+++ b/test/org/apache/catalina/servlets/TestDefaultServlet.java
@@ -164,6 +164,7 @@ public class TestDefaultServlet extends TomcatBaseTest {
     public void testCustomErrorPage() throws Exception {
         File appDir = new File(getTemporaryDirectory(), "MyApp");
         File webInf = new File(appDir, "WEB-INF");
+        addDeleteOnTearDown(appDir);
         if (!webInf.mkdirs() && !webInf.isDirectory()) {
             fail("Unable to create directory [" + webInf + "]");
         }
@@ -249,6 +250,7 @@ public class TestDefaultServlet extends TomcatBaseTest {
     public void testCustomErrorPageMissing() throws Exception {
         File appDir = new File(getTemporaryDirectory(), "MyApp");
         File webInf = new File(appDir, "WEB-INF");
+        addDeleteOnTearDown(appDir);
         if (!webInf.mkdirs() && !webInf.isDirectory()) {
             fail("Unable to create directory [" + webInf + "]");
         }
diff --git a/test/org/apache/catalina/session/Benchmarks.java b/test/org/apache/catalina/session/Benchmarks.java
index 9376dba..1e6c545 100644
--- a/test/org/apache/catalina/session/Benchmarks.java
+++ b/test/org/apache/catalina/session/Benchmarks.java
@@ -152,7 +152,7 @@ public class Benchmarks {
      * 16 threads - ~45,600ms
      */
     @Test
-    public void testManagerBaseCreateSession() throws LifecycleException {
+    public void testManagerBaseCreateSession() {
         doTestManagerBaseCreateSession(1, 1000000);
         doTestManagerBaseCreateSession(2, 1000000);
         doTestManagerBaseCreateSession(4, 1000000);
@@ -163,8 +163,8 @@ public class Benchmarks {
     }
     
     
-    private void doTestManagerBaseCreateSession(int threadCount, int iterCount)
-            throws LifecycleException {
+    private void doTestManagerBaseCreateSession(int threadCount,
+            int iterCount) {
 
         // Create a default session manager
         StandardManager mgr = new StandardManager();
diff --git a/java/org/apache/naming/resources/ImmutableNameNotFoundException.java b/test/org/apache/catalina/startup/FastNonSecureRandom.java
similarity index 50%
copy from java/org/apache/naming/resources/ImmutableNameNotFoundException.java
copy to test/org/apache/catalina/startup/FastNonSecureRandom.java
index a33da75..45a196f 100644
--- a/java/org/apache/naming/resources/ImmutableNameNotFoundException.java
+++ b/test/org/apache/catalina/startup/FastNonSecureRandom.java
@@ -13,40 +13,48 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */ 
-
-package org.apache.naming.resources;
+ */
+package org.apache.catalina.startup;
 
-import javax.naming.Name;
-import javax.naming.NameNotFoundException;
+import java.security.SecureRandom;
+import java.util.Random;
 
-/**
- * Immutable exception to avoid useless object creation by the proxy context.
- * This should be used only by the proxy context. Actual contexts should return
- * properly populated exceptions.
- * 
- * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
- * @version $Revision: 1044987 $
- */
-public class ImmutableNameNotFoundException
-    extends NameNotFoundException {
+public class FastNonSecureRandom extends SecureRandom {
 
     private static final long serialVersionUID = 1L;
-    
-    @Override
-    public void appendRemainingComponent(String name) {/*NOOP*/}
+
+    private final Random random = new Random();
+
     @Override
-    public void appendRemainingName(Name name) {/*NOOP*/}
+    public String getAlgorithm() {
+        return "INSECURE";
+    }
+
     @Override
-    public void setRemainingName(Name name) {/*NOOP*/}
+    public synchronized void setSeed(byte[] seed) {
+        // Not implemented
+    }
+
     @Override
-    public void setResolvedName(Name name) {/*NOOP*/}
+    public synchronized void setSeed(long seed) {
+        // The super class constructor calls this method earlier than our
+        // fields are initialized. Ignore the call.
+        if (random == null) {
+            return;
+        }
+        random.setSeed(seed);
+    }
+
     @Override
-    public void setRootCause(Throwable e) {/*NOOP*/}
+    public synchronized void nextBytes(byte[] bytes) {
+        random.nextBytes(bytes);
+    }
 
     @Override
-    public synchronized Throwable fillInStackTrace() {
-        // This class does not provide a stack trace
-        return this;
+    public byte[] generateSeed(int numBytes) {
+        byte[] value = new byte[numBytes];
+        nextBytes(value);
+        return value;
     }
-}
+
+}
\ No newline at end of file
diff --git a/test/org/apache/catalina/startup/TomcatBaseTest.java b/test/org/apache/catalina/startup/TomcatBaseTest.java
index 32d4d48..3720bf3 100644
--- a/test/org/apache/catalina/startup/TomcatBaseTest.java
+++ b/test/org/apache/catalina/startup/TomcatBaseTest.java
@@ -24,6 +24,7 @@ import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -37,10 +38,15 @@ import static org.junit.Assert.fail;
 import org.junit.After;
 import org.junit.Before;
 
+import org.apache.catalina.Container;
+import org.apache.catalina.LifecycleException;
 import org.apache.catalina.LifecycleState;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.core.AprLifecycleListener;
 import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.session.StandardManager;
 import org.apache.catalina.valves.AccessLogValve;
 import org.apache.tomcat.util.buf.ByteChunk;
 
@@ -56,6 +62,8 @@ public abstract class TomcatBaseTest {
 
     public static final String TEMP_DIR = System.getProperty("java.io.tmpdir");
 
+    private List<File> deleteOnTearDown = new ArrayList<File>();
+
     /**
      * Make Tomcat instance accessible to sub-classes.
      */
@@ -80,8 +88,15 @@ public abstract class TomcatBaseTest {
 
     /**
      * Helper method that returns the path of the temporary directory used by
-     * the test runs. The directory is configured during {@link #setUp()} and is
-     * deleted at {@link #tearDown()}.
+     * the test runs. The directory is configured during {@link #setUp()}.
+     * 
+     * <p>
+     * It is used as <code>${catalina.base}</code> for the instance of Tomcat
+     * that is being started, but can be used to store other temporary files as
+     * well. Its <code>work</code> and <code>webapps</code> subdirectories are
+     * deleted at {@link #tearDown()}. If you have other files or directories
+     * that have to be deleted on cleanup, register them with
+     * {@link #addDeleteOnTearDown(File)}.
      */
     public File getTemporaryDirectory() {
         return tempDir;
@@ -104,6 +119,17 @@ public abstract class TomcatBaseTest {
         return accessLogEnabled;
     }
 
+    /**
+     * Schedule the given file or directory to be deleted during after-test
+     * cleanup.
+     * 
+     * @param file
+     *            File or directory
+     */
+    public void addDeleteOnTearDown(File file) {
+        deleteOnTearDown.add(file);
+    }
+
     @Before
     public void setUp() throws Exception {
         // Need to use JULI so log messages from the tests are visible
@@ -126,7 +152,7 @@ public abstract class TomcatBaseTest {
             fail("Unable to create appBase for test");
         }
         
-        tomcat = new Tomcat();
+        tomcat = new TomcatWithFastSessionIDs();
 
         String protocol = getProtocol();
         Connector connector = new Connector(protocol);
@@ -184,7 +210,15 @@ public abstract class TomcatBaseTest {
             }
             tomcat.destroy();
         }
-        ExpandWar.delete(tempDir);
+        // Cannot delete the whole tempDir, because logs are there,
+        // and they might be open for writing.
+        // Delete known subdirectories of it.
+        deleteOnTearDown.add(new File(tempDir, "webapps"));
+        deleteOnTearDown.add(new File(tempDir, "work"));
+        for (File file : deleteOnTearDown) {
+            ExpandWar.delete(file);
+        }
+        deleteOnTearDown.clear();
     }
     
     /**
@@ -358,4 +392,27 @@ public abstract class TomcatBaseTest {
         return rc;
     }
 
+    private static class TomcatWithFastSessionIDs extends Tomcat {
+
+        @Override
+        public void start() throws LifecycleException {
+            // Use fast, insecure session ID generation for all tests
+            Server server = getServer();
+            for (Service service : server.findServices()) {
+                Container e = service.getContainer();
+                for (Container h : e.findChildren()) {
+                    for (Container c : h.findChildren()) {
+                        StandardManager m = (StandardManager) c.getManager();
+                        if (m == null) {
+                            m = new StandardManager();
+                            m.setSecureRandomClass(
+                                    "org.apache.catalina.startup.FastNonSecureRandom");
+                            c.setManager(m);
+                        }
+                    }
+                }
+            }
+            super.start();
+        }
+    }
 }
diff --git a/test/org/apache/catalina/tribes/test/channel/TestDataIntegrity.java b/test/org/apache/catalina/tribes/test/channel/TestDataIntegrity.java
index 2a77a5c..d863525 100644
--- a/test/org/apache/catalina/tribes/test/channel/TestDataIntegrity.java
+++ b/test/org/apache/catalina/tribes/test/channel/TestDataIntegrity.java
@@ -49,9 +49,6 @@ public class TestDataIntegrity {
     private GroupChannel channel2;
     private Listener listener1;
 
-    @SuppressWarnings("unused")
-    private int threadCounter = 0;
-
     @Before
     public void setUp() throws Exception {
         channel1 = new GroupChannel();
@@ -85,8 +82,6 @@ public class TestDataIntegrity {
                     }catch ( Exception x ) {
                         x.printStackTrace();
                         return;
-                    } finally {
-                        threadCounter++;
                     }
                 }
             };
@@ -115,8 +110,6 @@ public class TestDataIntegrity {
                         }catch ( Exception x ) {
                             x.printStackTrace();
                             return;
-                        } finally {
-                            threadCounter++;
                         }
                     }
                 };
diff --git a/test/org/apache/catalina/tribes/test/channel/TestMulticastPackages.java b/test/org/apache/catalina/tribes/test/channel/TestMulticastPackages.java
index b325ddc..354d5cd 100644
--- a/test/org/apache/catalina/tribes/test/channel/TestMulticastPackages.java
+++ b/test/org/apache/catalina/tribes/test/channel/TestMulticastPackages.java
@@ -49,9 +49,6 @@ public class TestMulticastPackages {
     private GroupChannel channel2;
     private Listener listener1;
 
-    @SuppressWarnings("unused")
-    private int threadCounter = 0;
-
     @Before
     public void setUp() throws Exception {
         channel1 = new GroupChannel();
@@ -128,8 +125,6 @@ public class TestMulticastPackages {
                     }catch ( Exception x ) {
                         x.printStackTrace();
                         return;
-                    } finally {
-                        threadCounter++;
                     }
                 }
             };
diff --git a/test/org/apache/catalina/tribes/test/channel/TestUdpPackages.java b/test/org/apache/catalina/tribes/test/channel/TestUdpPackages.java
index e3a66e5..0c9a2aa 100644
--- a/test/org/apache/catalina/tribes/test/channel/TestUdpPackages.java
+++ b/test/org/apache/catalina/tribes/test/channel/TestUdpPackages.java
@@ -49,9 +49,6 @@ public class TestUdpPackages {
     private GroupChannel channel2;
     private Listener listener1;
 
-    @SuppressWarnings("unused")
-    private int threadCounter = 0;
-
     @Before
     public void setUp() throws Exception {
         channel1 = new GroupChannel();
@@ -120,8 +117,6 @@ public class TestUdpPackages {
                     }catch ( Exception x ) {
                         x.printStackTrace();
                         return;
-                    } finally {
-                        threadCounter++;
                     }
                 }
             };
@@ -171,8 +166,6 @@ public class TestUdpPackages {
                     }catch ( Exception x ) {
                         x.printStackTrace();
                         return;
-                    } finally {
-                        threadCounter++;
                     }
                 }
             };
diff --git a/test/org/apache/coyote/ajp/TesterAjpMessage.java b/test/org/apache/coyote/ajp/TesterAjpMessage.java
index 2a84f9a..8835c64 100644
--- a/test/org/apache/coyote/ajp/TesterAjpMessage.java
+++ b/test/org/apache/coyote/ajp/TesterAjpMessage.java
@@ -17,7 +17,7 @@
 package org.apache.coyote.ajp;
 
 /**
- * Extends {@link AjpMessage} to provide additional methods for writing to the
+ * Extends {@link AjpMessage} to provide additional methods for reading from the
  * message.
  * TODO: See if it makes sense for any/all of these methods to be transferred to
  *       AjpMessage
diff --git a/test/org/apache/naming/resources/TestNamingContext.java b/test/org/apache/naming/resources/TestNamingContext.java
index 64720ec..8777ded 100644
--- a/test/org/apache/naming/resources/TestNamingContext.java
+++ b/test/org/apache/naming/resources/TestNamingContext.java
@@ -214,5 +214,61 @@ public class TestNamingContext extends TomcatBaseTest {
         }
     }
     
+    @Test
+    public void testBug51744() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        tomcat.enableNaming();
+        
+        // Must have a real docBase - just use temp
+        StandardContext ctx = (StandardContext)
+            tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+        
+        // Map the test Servlet
+        Bug51744Servlet bug51744Servlet = new Bug51744Servlet();
+        Tomcat.addServlet(ctx, "bug51744Servlet", bug51744Servlet);
+        ctx.addServletMapping("/", "bug51744Servlet");
+
+        tomcat.start();
+
+        ByteChunk bc = new ByteChunk();
+        int rc = getUrl("http://localhost:" + getPort() + "/", bc, null);
+        assertEquals(200, rc);
+        assertEquals(Bug51744Servlet.EXPECTED, bc.toString());
+    }
+
+    public static final class Bug51744Servlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        public static final String EXPECTED = "TestValue";
 
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+
+            resp.setContentType("text/plain;UTF-8");
+            PrintWriter out = resp.getWriter();
+
+            try {
+                Context ctx1 = new InitialContext();
+                Context env1 = (Context) ctx1.lookup("java:comp/env");
+                env1.addToEnvironment("TestName", EXPECTED);
+
+                boolean error = false;
+                try {
+                    env1.close();
+                } catch (NamingException ne) {
+                    error = true;
+                }
+                if (!error) {
+                    throw new ServletException(
+                            "No error when one was expected");
+                }
+                
+                out.print(env1.getEnvironment().get("TestName"));
+            } catch (NamingException ne) {
+                ne.printStackTrace(out);
+            }
+        }
+    }
 }
diff --git a/test/org/apache/tomcat/util/net/TestCustomSsl.java b/test/org/apache/tomcat/util/net/TestCustomSsl.java
index 0cdaf6b..ea10715 100644
--- a/test/org/apache/tomcat/util/net/TestCustomSsl.java
+++ b/test/org/apache/tomcat/util/net/TestCustomSsl.java
@@ -54,7 +54,7 @@ public class TestCustomSsl extends TomcatBaseTest {
             return;
         }
 
-        connector.setProperty("sslImplemenationName", 
+        connector.setProperty("sslImplementationName", 
                 "org.apache.tomcat.util.net.jsse.TesterBug50640SslImpl");
         connector.setProperty(TesterBug50640SslImpl.PROPERTY_NAME,
                 TesterBug50640SslImpl.PROPERTY_VALUE);
diff --git a/test/org/apache/tomcat/util/threads/TestLimitLatch.java b/test/org/apache/tomcat/util/threads/TestLimitLatch.java
index 391b4a9..e9638e7 100644
--- a/test/org/apache/tomcat/util/threads/TestLimitLatch.java
+++ b/test/org/apache/tomcat/util/threads/TestLimitLatch.java
@@ -92,7 +92,7 @@ public class TestLimitLatch {
         assertFalse("No threads should be waiting", latch.hasQueuedThreads());
     }
 
-    private class TestThread extends Thread {
+    private static class TestThread extends Thread {
         
         private int holdTime;
         private LimitLatch latch;
diff --git a/test/webapp-3.0-servletsecurity2/protected.jsp b/test/webapp-3.0/annotations.jsp
similarity index 82%
copy from test/webapp-3.0-servletsecurity2/protected.jsp
copy to test/webapp-3.0/annotations.jsp
index 535c611..180743d 100644
--- a/test/webapp-3.0-servletsecurity2/protected.jsp
+++ b/test/webapp-3.0/annotations.jsp
@@ -14,10 +14,15 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 --%>
+<%@page import="javax.annotation.PostConstruct"%>
 <html>
-  <head><title>Protected page</title></head>
+  <head><title>Annotations test case</title></head>
   <body>
-    <p>00-OK</p>
+    <p>Hello world</p>
   </body>
 </html>
-
+<%!
+  @PostConstruct
+  public void doNothing() {
+  }
+%>
\ No newline at end of file
diff --git a/webapps/docs/appdev/sample/src/mypackage/Hello.java b/webapps/docs/appdev/sample/src/mypackage/Hello.java
index 3a2341e..ea109ce 100644
--- a/webapps/docs/appdev/sample/src/mypackage/Hello.java
+++ b/webapps/docs/appdev/sample/src/mypackage/Hello.java
@@ -36,6 +36,7 @@ import javax.servlet.http.HttpServletResponse;
 
 public final class Hello extends HttpServlet {
 
+    private static final long serialVersionUID = 1L;
 
     /**
      * Respond to a GET request for the content produced by
@@ -47,6 +48,7 @@ public final class Hello extends HttpServlet {
      * @exception IOException if an input/output error occurs
      * @exception ServletException if a servlet error occurs
      */
+    @Override
     public void doGet(HttpServletRequest request,
                       HttpServletResponse response)
       throws IOException, ServletException {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index f130b2f..12267a7 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -53,7 +53,232 @@
   They eventually become mixed with the numbered issues. (I.e., numbered
   issues to not "pop up" wrt. others).
 -->
-<section name="Tomcat 7.0.21 (markt)">
+<section name="Tomcat 7.0.22 (markt)">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>51550</bug>: An additional change that ensures any exceptions
+        thrown by an Authenticator (or any other Valve configured for the
+        Context) will be handled by the custom error pages for the Context if an
+        appropriate error page is configured. (markt) 
+      </fix>
+      <fix>
+        <bug>51580</bug>: Added a nicer error message when a WAR file contains
+        filenames not properly encoded in UTF-8. (schultz)
+      </fix>
+      <fix>
+        <bug>51687</bug>: Added (optional) protection against
+        sun.java2d.Disposer thread pinning a WebappClassLoader into memory
+        in the JreMemoryLeakPreventionListener. (schultz)
+      </fix>
+      <add>
+        <bug>51741</bug>: Fixes a problem with Eclipse WTP "Serve modules
+        without publishing" feature where applications failed to access
+        resources when using getResource() on the classloader. (slaurent)
+      </add>
+      <fix>
+        <bug>51744</bug>: Prevent application code from closing the associated
+        JNDI context while the application is running. (markt)
+      </fix>
+      <fix>
+        Correct a regression with the fix for <bug>51653</bug> that broke custom
+        error pages for 4xx responses from the Authenticators. Error handling
+        and request listeners are now handled in the StandardHostValve to ensure
+        they wrap all Context level activity. (markt)
+      </fix>
+      <fix>
+        <bug>51758</bug>: The digester (used for processing XML files) used the
+        logger name <code>org.apache.commons.digester.Digester</code> rather
+        than the expected <code>org.apache.tomcat.util.digester.Digester</code>.
+        The digester has been changed to use the expected logger name.
+        (markt/kkolinko)
+      </fix>
+      <fix>
+        <bug>51774</bug>: Fix incorrect cached method signature that prevented
+        session tracking modes from being defined in web.xml when running under
+        a security manager. (markt) 
+      </fix>
+      <add>
+        Add an annotation cache to the <code>DefaultInstanceManager</code> that
+        improves performance for applications that make use of a lot of
+        non-poolable objects (e.g. tag files) that need to be scanned for
+        annotations when created. (markt)
+      </add>
+      <fix>
+        Use the specification compliant request attribute of
+        <code>javax.servlet.request.ssl_session_id</code> to access the SSL
+        session ID and deprecated the Tomcat specific request attribute. (markt)
+      </fix>
+      <add>
+        Allow to overwrite the check for distributability
+        of session attributes by session implementations. (rjung)
+      </add>
+      <update>
+        Add Java 7 sunec.jar and zipfs.jar to the list of JARs
+        to skip when scanning for TLDs and web fragments. (rjung)
+      </update>
+      <add>
+        <bug>51862</bug>: Added a <code>classesToInitialize</code> attribute to 
+        <code>JreMemoryLeakPreventionListener</code> to allow pre-loading of configurable
+        classes to avoid some classloader leaks. (slaurent)
+      </add>
+      <fix>
+        Reduce visibility of static field <code>ManagerBase.name</code> and
+        make it final. (kkolinko)
+      </fix>
+      <update>
+        Add thread name to juli OneLineFormatter. (rjung)
+      </update>
+      <fix>
+        Ensure Servlets that implement ContainerServlet always get treated as
+        restricted. (markt)
+      </fix>
+      <fix>
+        Ensure that the access log always uses the correct value for the remote
+        IP address associated with the request and that requests with multiple
+        errors do not result in multiple entires in the access log. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <scode>
+        Remove unused and undocumented socketCloseDelay attribute from NIO
+        connector. (markt)
+      </scode>
+      <fix>
+        <bug>49683</bug>: Support separate connection and keep-alive timeouts
+        for the APR/native connector HTTP and AJP connectors. (markt)
+      </fix>
+      <scode>
+        Further re-factoring of the HTTP connectors to align the BIO, NIO and
+        APR implementations. (markt) 
+      </scode>
+      <fix>
+        <bug>51794</bug>: Fix race condition in NioEndpoint. (fhanik)
+      </fix>
+      <fix>
+        <bug>51811</bug>: Correct SSL configuration property name from
+        sslImplemenationName to sslImplementationName. (rjung)
+      </fix>
+      <fix>
+        Fix a timing issue in NIO connector that meant that stopping a connector
+        did not trigger a Comet END event if the associated processor was
+        processing a READ event when the connector was stopped. (markt)
+      </fix>
+      <fix>
+        Replace unneeded call that iterated events queue in NioEndpoint.Poller.
+        (kkolinko)
+      </fix>
+      <fix>
+        <bug>51860</bug>: Fix issues if using NIO with a custom
+        SSLImplementation. Based on a suggestion by Roman Tsirulnikov. (markt)
+      </fix>
+      <fix>
+        Allow the BIO HTTP connector to be used with SSL when running under Java
+        7. (markt)
+      </fix>
+      <update>
+        Don't send AJP CPONG if endpoint is already paused. (rjung)
+      </update>
+      <update>
+        Align APR AJP connector with NIO one. Send 503 if endpoint is paused.
+        (rjung)
+      </update>
+      <update>
+        Accept AJP request even if endpoint is paused, if CPING was successful.
+        (rjung)
+      </update>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        When unloading JSPs due to configuration of the
+        <code>maxLoadedJsps</code> initialisation parameter, the unloading code
+        was retaining a reference to the to the unloaded JSP preventing the
+        associated class from being unloaded until the JSP that replaced it was
+        itself unloaded. (markt) 
+      </fix>
+      <fix>
+        <bug>51852</bug>: Correct two problems in the handling of varargs
+        methods with the BeanELResolver. The first meant the wrong method was
+        sometimes called and the second that an ArrayIndexOutOfBoundsExceptions
+        could be thrown. Patch (including a test case) provided by Matt Benson.
+        (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <update>
+        Refactor cluster manager configuration: move handling of common
+        attributes to base class. (kfujino, rjung)
+      </update>
+      <add>
+        New cluster manager attribute <code>sessionAttributeFilter</code>
+        allows to filter which session attributes are replicated using a
+        regular expression applied to the attribute name. (rjung)
+      </add>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <fix>
+        Correct the documentation for <code>connectionLinger</code> attribute
+        for the AJP and HTTP connectors. (markt)
+      </fix>
+      <update>
+        Document caveat of using <code>RemoteAddrValve</code> with IPv6
+        addresses. (kkolinko)
+      </update>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <fix>
+        In jdbc-pool: Avoid IllegalArgumentException when setting maxActive 
+        less than or equal to 0.
+        ArrayBlockingQueue doesn't allow capacity of 0 or less. (kfujino)
+      </fix>
+      <fix>
+        <bug>48392</bug> (<rev>1169796</rev>): In jdbc-pool: Fix typo in
+        <code>StatementDecoratorInterceptor</code>. (fhanik) 
+      </fix>
+      <fix>
+        <bug>51139</bug>:
+        In jdbc-pool: validatorClassName and suspectTimeout are ignored. 
+        In order to support them correctly, validatorClassName and 
+        suspectTimeout are added to a property list. (kfujino)
+      </fix>
+      <fix>
+        <bug>51786</bug>:
+        In jdbc-pool: Discarded connection is not active in a pool any longer. 
+        It removes from the active connection list. (kfujino)
+      </fix>
+      <fix>
+        <bug>51871</bug>: In jdbc-pool: Fix dependency in Maven POM file of
+        tomcat-jbdc. (kkolinko)
+      </fix>
+      <update>
+        Update the "test" target in the default build file to report a test
+        failure only after all available connector variants (bio, nio, apr)
+        have been tested. Do not stop after first connector that fails.
+        (kkolinko)
+      </update>
+      <update>
+        <bug>51887</bug>: When running the unit tests, use a fast but insecure
+        random number source for session ID generation to reduce the delays
+        caused by waiting for entropy. (kkolinko/markt)
+      </update>
+      <scode>
+        Code clean-up to further reduce the number of warnings reported by
+        Eclipse, FindBugs and CheckStyle. (markt/kkolinko)
+      </scode>
+    </changelog>
+  </subsection>  
+</section>
+<section name="Tomcat 7.0.21 (markt)" rtext="released 2011-09-01">
   <subsection name="Catalina">
     <changelog>
       <add>
@@ -1416,10 +1641,6 @@
         suggested by Werner Donn. (markt)
       </add>
       <fix>
-        <bug>50929</bug>: When wrapping an exception, include the root cause.
-        Patch provided by sebb. (markt) 
-      </fix>
-      <fix>
         Make the CSRF nonce cache serializable so that it can be replicated
         across a cluster and/or persisted across Tomcat restarts. (markt)
       </fix>
@@ -1458,6 +1679,10 @@
         since this too cannot be reliably determined. (markt)
       </fix>
       <fix>
+        <bug>50929</bug>: When wrapping an exception, include the root cause.
+        Patch provided by sebb. (markt) 
+      </fix>
+      <fix>
         <bug>50991</bug>: Fix regression in fix for <bug>25060</bug> that called
         close on a JNDI resource while it was still available to the
         application. (markt)
@@ -1485,8 +1710,8 @@
         Don't register non-singelton DataSource resources with JMX. (markt)
       </fix>
       <add>
-        Provide additional configuration options for the DIGEST authenticator.
-        (markt)
+        CVE-2011-1184: Provide additional configuration options for the DIGEST
+        authenticator. (markt)
       </add>
       <fix>
         Provide a workaround for Tomcat hanging during shutdown when running the
@@ -1985,7 +2210,8 @@
       </fix>
       <fix>
         Improve HTTP specification compliance in support of
-        <code>Accept-Language</code> header. (kkolinko)
+        <code>Accept-Language</code> header. This protects from known exploit
+        of the Oracle JVM bug that triggers a DoS, CVE-2010-4476. (kkolinko)
       </fix>
     </changelog>
   </subsection>
diff --git a/webapps/docs/config/ajp.xml b/webapps/docs/config/ajp.xml
index 443ca3a..149b078 100644
--- a/webapps/docs/config/ajp.xml
+++ b/webapps/docs/config/ajp.xml
@@ -292,9 +292,9 @@
     </attribute>
 
     <attribute name="connectionLinger" required="false">
-      <p>The number of milliseconds during which the sockets used by this
+      <p>The number of seconds during which the sockets used by this
       <strong>Connector</strong> will linger when they are closed.
-      The default value <code>-1</code> which disables this option.</p>
+      If not specified, the JVM default will be used.</p>
     </attribute>
 
     <attribute name="connectionTimeout" required="false">
diff --git a/webapps/docs/config/cluster-manager.xml b/webapps/docs/config/cluster-manager.xml
index 8e92c71..107f189 100644
--- a/webapps/docs/config/cluster-manager.xml
+++ b/webapps/docs/config/cluster-manager.xml
@@ -83,6 +83,15 @@
         sessions to expire on all nodes when a shutdown occurs on one node, set
         this value to <code>true</code>. Default value is <code>false</code>.
       </attribute>
+      <attribute name="sessionAttributeFilter" required="false">
+        A regular expression used to filter, which session attributes will
+        be replicated. An attribute will only be replicated, if its name
+        matches this pattern. If the pattern is not set (default), all
+        attributes are eligible for replication. As an example, the value
+        <code>^(userName|sessionHistory)$</code> will only replicate the two
+        session attributes named <code>userName</code> and
+        <code>sessionHistory</code>.
+      </attribute>
     </attributes>
   </subsection> 
   <subsection name="org.apache.catalina.ha.session.DeltaManager Attributes">
diff --git a/webapps/docs/config/filter.xml b/webapps/docs/config/filter.xml
index 49bd27f..707c667 100644
--- a/webapps/docs/config/filter.xml
+++ b/webapps/docs/config/filter.xml
@@ -531,6 +531,15 @@ FINE: Request "/docs/config/manager.html" with response status "200" content-typ
     package. Please consult the Java documentation for details of the
     expressions supported.</p>
 
+    <p><strong>Note:</strong> There is a caveat when using this filter with
+    IPv6 addresses. Format of the IP address that this valve is processing
+    depends on the API that was used to obtain it. If the address was obtained
+    from Java socket using Inet6Address class, its format will be
+    <code>x:x:x:x:x:x:x:x</code>. That is, the IP address for localhost
+    will be <code>0:0:0:0:0:0:0:1</code> instead of the more widely used
+    <code>::1</code>. Consult your access logs for the actual value.</p>
+
+    <p>See also: <a href="#Remote_Host_Filter">Remote Host Filter</a>.</p>
   </subsection>
 
   <subsection name="Filter Class Name">
@@ -569,6 +578,24 @@ FINE: Request "/docs/config/manager.html" with response status "200" content-typ
 
   </subsection>
 
+  <subsection name="Example">
+    <p>To allow access only for the clients connecting from localhost:</p>
+<pre>
+    <filter>
+      <filter-name>Remote Address Filter</filter-name>
+      <filter-class>org.apache.catalina.filters.RemoteAddrFilter</filter-class>
+      <init-param>
+        <param-name>allow</param-name>
+        <param-value>127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1</param-value>
+      </init-param>
+    </filter>
+    <filter-mapping>
+      <filter-name>Remote Address Filter</filter-name>
+      <url-pattern>/*</url-pattern>
+    </filter-mapping>
+</pre>
+  </subsection>
+
 </section>
 
 
@@ -586,6 +613,7 @@ FINE: Request "/docs/config/manager.html" with response status "200" content-typ
     package. Please consult the Java documentation for details of the
     expressions supported.</p>
 
+    <p>See also: <a href="#Remote_Address_Filter">Remote Address Filter</a>.</p>
   </subsection>
 
   <subsection name="Filter Class Name">
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index 7219c4f..3e34cd3 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -309,15 +309,18 @@
     </attribute>
 
     <attribute name="connectionLinger" required="false">
-      <p>The number of milliseconds during which the sockets used by this
+      <p>The number of seconds during which the sockets used by this
       <strong>Connector</strong> will linger when they are closed.
-      The default value <code>-1</code> which disables this option.</p>
+      If not specified, the JVM default will be used.</p>
     </attribute>
 
     <attribute name="connectionTimeout" required="false">
       <p>The number of milliseconds this <strong>Connector</strong> will wait,
       after accepting a connection, for the request URI line to be
-      presented.  The default value is 60000 (i.e. 60 seconds).</p>
+      presented. Use a value of -1 to indicate no (i.e. infinite) timeout.
+      The default value is 60000 (i.e. 60 seconds) but note that the standard
+      server.xml that ships with Tomcat sets this to 20000 (i.e. 20 seconds).
+      </p>
     </attribute>
     
     <attribute name="connectionUploadTimeout" required="false">
@@ -347,7 +350,8 @@
       <p>The number of milliseconds this <strong>Connector</strong> will wait
       for another HTTP request before closing the connection. The default value
       is to use the value that has been set for the
-      <strong>connectionTimeout</strong> attribute.</p>
+      <strong>connectionTimeout</strong> attribute.
+      Use a value of -1 to indicate no (i.e. infinite) timeout.</p>
     </attribute>
 
     <attribute name="maxConnections" required="false">
@@ -986,7 +990,7 @@
       used.</p>
     </attribute>
 
-    <attribute name="sslImplemenationName" required="false">
+    <attribute name="sslImplementationName" required="false">
       <p>The class name of the SSL implementation to use. If not specified, the
       default of <code>org.apache.tomcat.util.net.jsse.JSSEImplementation</code>
       will be used which wraps JVM's default JSSE provider. Note that the
diff --git a/webapps/docs/config/listeners.xml b/webapps/docs/config/listeners.xml
index 1900e7b..ef29c3c 100644
--- a/webapps/docs/config/listeners.xml
+++ b/webapps/docs/config/listeners.xml
@@ -181,6 +181,16 @@
         Defaults to <code>false</code> because an AWT thread is launched.</p>
       </attribute>
 
+      <attribute name="classesToInitialize" required="false">
+        <p>List of comma-separated fully qualified class names to load and initialize 
+        during the startup of this Listener. This allows to pre-load classes that are 
+        known to provoke classloader leaks if they are loaded during a request 
+        processing. Non-JRE classes may be referenced, like 
+        <code>oracle.jdbc.driver.OracleTimeoutThreadPerVM</code>.
+        The default value is empty, but specific JRE classes are loaded by other leak 
+        protection features managed by other attributes of this Listener.</p>
+      </attribute>
+
       <attribute name="driverManagerProtection" required="false">
         <p>The first use of <code>java.sql.DriverManager</code> will trigger the
         loading of JDBNC Driver in the the current class loader. The web
@@ -199,6 +209,13 @@
         startup on non-Sun JVMs. The default is <code>true</code>.</p>
       </attribute>
 
+      <attribute name="java2DDisposerProtection" required="false">
+        <p>Enables protection so that loading the
+        <code>sun.java2d.Disposer</code> class by a web application does not
+        result in a memory leak.
+        Defaults to <code>false</code> because a thread is launched.</p>
+      </attribute>
+
       <attribute name="ldapPoolProtection" required="false">
         <p>Enables protection so that the PoolCleaner thread started by
         <code>com.sun.jndi.ldap.LdapPoolManager</code> does not result in a 
diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml
index 3272733..9572e6a 100644
--- a/webapps/docs/config/valve.xml
+++ b/webapps/docs/config/valve.xml
@@ -509,6 +509,16 @@
     package. Please consult the Java documentation for details of the
     expressions supported.</p>
 
+    <p><strong>Note:</strong> There is a caveat when using this valve with
+    IPv6 addresses. Format of the IP address that this valve is processing
+    depends on the API that was used to obtain it. If the address was obtained
+    from Java socket using Inet6Address class, its format will be
+    <code>x:x:x:x:x:x:x:x</code>. That is, the IP address for localhost
+    will be <code>0:0:0:0:0:0:0:1</code> instead of the more widely used
+    <code>::1</code>. Consult your access logs for the actual value.</p>
+
+    <p>See also: <a href="#Remote_Host_Filter">Remote Host Filter</a>,
+    <a href="#Remote_IP_Valve">Remote IP Valve</a>.</p>
   </subsection>
 
   <subsection name="Attributes">
@@ -544,6 +554,14 @@
 
   </subsection>
 
+  <subsection name="Example">
+    <p>To allow access only for the clients connecting from localhost:</p>
+<pre>
+    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
+       allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1"/>
+</pre>
+  </subsection>
+
 </section>
 
 
@@ -565,6 +583,7 @@
     package. Please consult the Java documentation for details of the
     expressions supported.</p>
 
+    <p>See also: <a href="#Remote_Address_Filter">Remote Address Filter</a>.</p>
   </subsection>
 
   <subsection name="Attributes">
diff --git a/webapps/docs/manager-howto.xml b/webapps/docs/manager-howto.xml
index 81ae2b0..bcfd7fd 100644
--- a/webapps/docs/manager-howto.xml
+++ b/webapps/docs/manager-howto.xml
@@ -159,7 +159,9 @@ the role <strong>manager-script</strong>.</p>
 
 <p>In addition to the password restrictions the Manager web application
 could be restricted by the remote IP address or host by adding a
-<code>RemoteAddrValve</code> or <code>RemoteHostValve</code>.  Here is
+<code>RemoteAddrValve</code> or <code>RemoteHostValve</code>.
+See <a href="config/valve.html#Remote_Address_Filter">valves documentation</a>
+for details. Here is
 an example of restricting access to the localhost by IP address:</p>
 <pre>
 <Context privileged="true">
diff --git a/webapps/docs/ssl-howto.xml b/webapps/docs/ssl-howto.xml
index 8451b1a..7d74d22 100644
--- a/webapps/docs/ssl-howto.xml
+++ b/webapps/docs/ssl-howto.xml
@@ -582,7 +582,7 @@ public class SessionTrackingModeListener implements ServletContextListener {
 <p>To access the SSL session ID from the request, use:<br />
 
   <code>
-    String sslID = (String)request.getAttribute("javax.servlet.request.ssl_session");
+    String sslID = (String)request.getAttribute("javax.servlet.request.ssl_session_id");
   </code>
 <br />
 For additional discussion on this area, please see
diff --git a/webapps/docs/tomcat-docs.xsl b/webapps/docs/tomcat-docs.xsl
index ce43110..3ec0550 100644
--- a/webapps/docs/tomcat-docs.xsl
+++ b/webapps/docs/tomcat-docs.xsl
@@ -17,7 +17,7 @@
 -->
 <!-- Content Stylesheet for "tomcat-docs" Documentation -->
 
-<!-- $Id: tomcat-docs.xsl 1036949 2010-11-19 17:18:04Z markt $ -->
+<!-- $Id: tomcat-docs.xsl 1175614 2011-09-25 22:48:41Z kkolinko $ -->
 
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="1.0">
@@ -109,10 +109,8 @@
         </xsl:if>
         </td>
         <td>
-          <font face="arial,helvetica,sanserif">
-            <h1><xsl:value-of select="$project/title"/></h1>
-            Version <xsl:value-of select="$version"/>, <xsl:value-of select="$build-date"/>
-          </font>
+          <h1><font face="arial,helvetica,sanserif"><xsl:value-of select="$project/title"/></font></h1>
+          <font face="arial,helvetica,sanserif">Version <xsl:value-of select="$version"/>, <xsl:value-of select="$build-date"/></font>
         </td>
         <td>
           <xsl:comment>APACHE LOGO</xsl:comment>
diff --git a/webapps/docs/tribes/tomcat-docs.xsl b/webapps/docs/tribes/tomcat-docs.xsl
deleted file mode 100644
index c839346..0000000
--- a/webapps/docs/tribes/tomcat-docs.xsl
+++ /dev/null
@@ -1,452 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one or more
-  contributor license agreements.  See the NOTICE file distributed with
-  this work for additional information regarding copyright ownership.
-  The ASF licenses this file to You under the Apache License, Version 2.0
-  (the "License"); you may not use this file except in compliance with
-  the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-<!-- Content Stylesheet for "tomcat-docs" Documentation -->
-
-<!-- $Id: tomcat-docs.xsl 1054620 2011-01-03 14:00:29Z rjung $ -->
-
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-  version="1.0">
-
-
-  <!-- Output method -->
-  <xsl:output method="html"
-            encoding="iso-8859-1"
-              indent="no"/>
-
-
-  <!-- Defined parameters (overrideable) -->
-  <xsl:param    name="home-name"        select="'The Tomcat Project'"/>
-  <xsl:param    name="home-href"        select="'http://tomcat.apache.org/'"/>
-  <xsl:param    name="home-logo"        select="'/images/tomcat.gif'"/>
-  <xsl:param    name="printer-logo"     select="'/images/printer.gif'"/>
-  <xsl:param    name="apache-logo"      select="'/images/asf-logo.gif'"/>
-  <xsl:param    name="relative-path"    select="'.'"/>
-  <xsl:param    name="void-image"       select="'/images/void.gif'"/>
-  <xsl:param    name="project-menu"     select="'menu'"/>
-  <xsl:param    name="standalone"       select="''"/>
-  <xsl:param    name="buglink"          select="'http://issues.apache.org/bugzilla/show_bug.cgi?id='"/>
-
-  <!-- Defined variables (non-overrideable) -->
-  <xsl:variable name="body-bg"          select="'#ffffff'"/>
-  <xsl:variable name="body-fg"          select="'#000000'"/>
-  <xsl:variable name="body-link"        select="'#525D76'"/>
-  <xsl:variable name="banner-bg"        select="'#525D76'"/>
-  <xsl:variable name="banner-fg"        select="'#ffffff'"/>
-  <xsl:variable name="sub-banner-bg"    select="'#828DA6'"/>
-  <xsl:variable name="sub-banner-fg"    select="'#ffffff'"/>
-  <xsl:variable name="source-color"     select="'#023264'"/>
-  <xsl:variable name="attributes-color" select="'#023264'"/>
-  <xsl:variable name="table-th-bg"      select="'#039acc'"/>
-  <xsl:variable name="table-td-bg"      select="'#a0ddf0'"/>
-
-  <!-- Process an entire document into an HTML page -->
-  <xsl:template match="document">
-  <xsl:variable name="project"
-              select="document('project.xml')/project"/>
-    <html>
-    <head>
-    <title><xsl:value-of select="project/title"/> - <xsl:value-of select="properties/title"/></title>
-    <xsl:for-each select="properties/author">
-      <xsl:variable name="name">
-        <xsl:value-of select="."/>
-      </xsl:variable>
-      <xsl:variable name="email">
-        <xsl:value-of select="@email"/>
-      </xsl:variable>
-      <meta name="author" value="{$name}"/>
-      <meta name="email" value="{$email}"/>
-    </xsl:for-each>
-    </head>
-
-    <body bgcolor="{$body-bg}" text="{$body-fg}" link="{$body-link}"
-          alink="{$body-link}" vlink="{$body-link}">
-
-    <table border="0" width="100%" cellspacing="0">
-
-      <xsl:comment>PAGE HEADER</xsl:comment>
-      <tr>
-        <td>
-        <xsl:if test="project/logo">
-          <xsl:variable name="alt">
-            <xsl:value-of select="project/logo"/>
-          </xsl:variable>
-          <xsl:variable name="home">
-            <xsl:value-of select="project/@href"/>
-          </xsl:variable>
-          <xsl:variable name="src">
-            <!--<xsl:value-of select="$relative-path"/>--><xsl:value-of select="project/logo/@href"/>
-          </xsl:variable>
-
-          <xsl:comment>PROJECT LOGO</xsl:comment>
-          <a href="{$home}">
-            <img src="{$src}" align="right" alt="{$alt}" border="0"/>
-          </a>
-        </xsl:if>
-        </td>
-        <td>
-          <font face="arial,helvetica,sanserif">
-            <h1><xsl:value-of select="$project/title"/></h1>
-          </font>
-        </td>
-        <td>
-          <xsl:comment>APACHE LOGO</xsl:comment>
-          <xsl:variable name="src">
-            <xsl:value-of select="$relative-path"/><xsl:value-of select="$apache-logo"/>
-          </xsl:variable>
-          <a href="http://www.apache.org/">
-            <img src="http://tomcat.apache.org/tomcat-5.5-doc/images/asf-logo.gif" align="right" alt="Apache Logo" border="0"/>
-          </a>
-        </td>
-      </tr>
-    </table>
-
-    <table border="0" width="100%" cellspacing="4">
-
-      <xsl:comment>HEADER SEPARATOR</xsl:comment>
-      <tr>
-        <td colspan="2">
-          <hr noshade="noshade" size="1"/>
-        </td>
-      </tr>
-
-      <tr>
-
-        <!-- Don't generate a menu if styling printer friendly docs -->
-        <xsl:if test="$project-menu = 'menu'">
-          <xsl:comment>LEFT SIDE NAVIGATION</xsl:comment>
-          <td width="20%" valign="top" nowrap="true">
-            <xsl:apply-templates select="project/body/menu"/>
-          </td>
-        </xsl:if>
-
-        <xsl:comment>RIGHT SIDE MAIN BODY</xsl:comment>
-        <td width="80%" valign="top" align="left">
-          <table border="0" width="100%" cellspacing="4">
-            <tr>
-              <td align="left" valign="top">
-                <h1><xsl:value-of select="project/title"/></h1>
-                <h2><xsl:value-of select="properties/title"/></h2>
-              </td>
-              <td align="right" valign="top" nowrap="true">
-                <!-- Add the printer friendly link for docs with a menu -->
-                <xsl:if test="$project-menu = 'menu'">
-                  <xsl:variable name="src">
-                    <xsl:value-of select="$relative-path"/><xsl:value-of select="$printer-logo"/>
-                  </xsl:variable>
-                  <xsl:variable name="url">
-                    <xsl:value-of select="/document/@url"/>
-                  </xsl:variable>
-                  <small>
-                    <a href="printer/{$url}">
-                      <img src="{$src}" border="0" alt="Printer Friendly Version"/>
-                      <br />print-friendly<br />version
-                    </a>
-                  </small>
-                </xsl:if>
-                <xsl:if test="$project-menu != 'menu'">
-                  <xsl:variable name="void">
-                    <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
-                    </xsl:variable>
-                  <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-                </xsl:if>
-              </td>
-            </tr>
-          </table>
-          <xsl:apply-templates select="body/section"/>
-        </td>
-
-      </tr>
-
-      <xsl:comment>FOOTER SEPARATOR</xsl:comment>
-      <tr>
-        <td colspan="2">
-          <hr noshade="noshade" size="1"/>
-        </td>
-      </tr>
-
-      <xsl:comment>PAGE FOOTER</xsl:comment>
-      <tr><td colspan="2">
-        <div align="center"><font color="{$body-link}" size="-1"><em>
-        Copyright © 1999-2011, Apache Software Foundation
-        </em></font></div>
-      </td></tr>
-
-    </table>
-    </body>
-    </html>
-
-  </xsl:template>
-
-
-  <!-- Process a menu for the navigation bar -->
-  <xsl:template match="menu">
-    <p><strong><xsl:value-of select="@name"/></strong></p>
-    <ul>
-      <xsl:apply-templates select="item"/>
-    </ul>
-  </xsl:template>
-
-
-  <!-- Process a menu item for the navigation bar -->
-  <xsl:template match="item">
-    <xsl:variable name="href">
-      <xsl:value-of select="@href"/>
-    </xsl:variable>
-    <li><a href="{$href}"><xsl:value-of select="@name"/></a></li>
-  </xsl:template>
-
-
-  <!-- Process a documentation section -->
-  <xsl:template match="section">
-    <xsl:variable name="name">
-      <xsl:value-of select="@name"/>
-    </xsl:variable>
-    <table border="0" cellspacing="0" cellpadding="2">
-      <!-- Section heading -->
-      <tr><td bgcolor="{$banner-bg}">
-          <font color="{$banner-fg}" face="arial,helvetica.sanserif">
-          <a name="{$name}">
-          <strong><xsl:value-of select="@name"/></strong></a></font>
-      </td></tr>
-      <!-- Section body -->
-      <tr><td><blockquote>
-        <xsl:apply-templates/>
-      </blockquote></td></tr>
-    </table>
-  </xsl:template>
-
-
-  <!-- Process a documentation subsection -->
-  <xsl:template match="subsection">
-    <xsl:variable name="name">
-      <xsl:value-of select="@name"/>
-    </xsl:variable>
-    <table border="0" cellspacing="0" cellpadding="2">
-      <!-- Subsection heading -->
-      <tr><td bgcolor="{$sub-banner-bg}">
-          <font color="{$sub-banner-fg}" face="arial,helvetica.sanserif">
-          <a name="{$name}">
-          <strong><xsl:value-of select="@name"/></strong></a></font>
-      </td></tr>
-      <!-- Subsection body -->
-      <tr><td><blockquote>
-        <xsl:apply-templates/>
-      </blockquote></td></tr>
-    </table>
-  </xsl:template>
-
-
-  <!-- Process a source code example -->
-  <xsl:template match="source">
-    <xsl:variable name="void">
-      <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
-    </xsl:variable>
-    <div align="left">
-      <table cellspacing="4" cellpadding="0" border="0">
-        <tr>
-          <td bgcolor="{$source-color}" width="1" height="1">
-            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-          </td>
-          <td bgcolor="{$source-color}" height="1">
-            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-          </td>
-          <td bgcolor="{$source-color}" width="1" height="1">
-            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-          </td>
-        </tr>
-        <tr>
-          <td bgcolor="{$source-color}" width="1">
-            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-          </td>
-          <td bgcolor="#ffffff" height="1"><pre>
-            <xsl:value-of select="."/>
-          </pre></td>
-          <td bgcolor="{$source-color}" width="1">
-            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-          </td>
-        </tr>
-        <tr>
-          <td bgcolor="{$source-color}" width="1" height="1">
-            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-          </td>
-          <td bgcolor="{$source-color}" height="1">
-            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-          </td>
-          <td bgcolor="{$source-color}" width="1" height="1">
-            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
-          </td>
-        </tr>
-      </table>
-    </div>
-  </xsl:template>
-
-
-  <!-- Process an attributes list with nested attribute elements -->
-  <xsl:template match="attributes">
-    <table border="1" cellpadding="5">
-      <tr>
-        <th width="15%" bgcolor="{$attributes-color}">
-          <font color="#ffffff">Attribute</font>
-        </th>
-        <th width="85%" bgcolor="{$attributes-color}">
-          <font color="#ffffff">Description</font>
-        </th>
-      </tr>
-      <xsl:for-each select="attribute">
-        <tr>
-          <td align="left" valign="center">
-            <xsl:if test="@required = 'true'">
-              <strong><code><xsl:value-of select="@name"/></code></strong>
-            </xsl:if>
-            <xsl:if test="@required != 'true'">
-              <code><xsl:value-of select="@name"/></code>
-            </xsl:if>
-          </td>
-          <td align="left" valign="center">
-            <xsl:apply-templates/>
-          </td>
-        </tr>
-      </xsl:for-each>
-    </table>
-  </xsl:template>
-
-  <!-- Fix relative links in printer friendly versions of the docs -->
-  <xsl:template match="a">
-    <xsl:variable name="href" select="@href"/>
-    <xsl:choose>
-      <xsl:when test="$standalone = 'standalone'">
-        <xsl:apply-templates/>
-      </xsl:when>
-      <xsl:when test="$project-menu != 'menu' and starts-with(@href,'../')">
-        <a href="../{$href}"><xsl:apply-templates/></a>
-      </xsl:when>
-      <xsl:when test="$project-menu != 'menu' and starts-with(@href,'./') and contains(substring(@href,3),'/')">
-        <a href=".{$href}"><xsl:apply-templates/></a>
-      </xsl:when>
-      <xsl:when test="$project-menu != 'menu' and not(contains(@href,'//')) and not(starts-with(@href,'/')) and not(starts-with(@href,'#')) and contains(@href,'/')">
-        <a href="../{$href}"><xsl:apply-templates/></a>
-      </xsl:when>
-      <xsl:when test="$href != ''">
-        <a href="{$href}"><xsl:apply-templates/></a>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:variable name="name" select="@name"/>
-        <a name="{$name}"><xsl:apply-templates/></a>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <!-- Changelog related tags -->
-  <xsl:template match="changelog">
-    <table border="0" cellpadding="2" cellspacing="2">
-      <xsl:apply-templates/>
-    </table>
-  </xsl:template>
-
-  <xsl:template match="changelog/add">
-    <tr>
-      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/add.gif</xsl:variable>
-      <td><img alt="add" class="icon" src="{$src}"/></td>
-      <td><xsl:apply-templates/></td>
-    </tr>
-  </xsl:template>
-
-  <xsl:template match="changelog/update">
-    <tr>
-      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/update.gif</xsl:variable>
-      <td><img alt="update" class="icon" src="{$src}"/></td>
-      <td><xsl:apply-templates/></td>
-    </tr>
-  </xsl:template>
-
-  <xsl:template match="changelog/design">
-    <tr>
-      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/design.gif</xsl:variable>
-      <td><img alt="design" class="icon" src="{$src}"/></td>
-      <td><xsl:apply-templates/></td>
-    </tr>
-  </xsl:template>
-
-  <xsl:template match="changelog/docs">
-    <tr>
-      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/docs.gif</xsl:variable>
-      <td><img alt="docs" class="icon" src="{$src}"/></td>
-      <td><xsl:apply-templates/></td>
-    </tr>
-  </xsl:template>
-
-  <xsl:template match="changelog/fix">
-    <tr>
-      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/fix.gif</xsl:variable>
-      <td><img alt="fix" class="icon" src="{$src}"/></td>
-      <td><xsl:apply-templates/></td>
-    </tr>
-  </xsl:template>
-
-  <xsl:template match="changelog/scode">
-    <tr>
-      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/code.gif</xsl:variable>
-      <td><img alt="code" class="icon" src="{$src}"/></td>
-      <td><xsl:apply-templates/></td>
-    </tr>
-  </xsl:template>
-
-  <!-- Process an attributes list with nested attribute elements -->
-  <xsl:template match="status">
-    <table border="1" cellpadding="5">
-      <tr>
-        <th width="15%" bgcolor="{$attributes-color}">
-          <font color="#ffffff">Priority</font>
-        </th>
-        <th width="50%" bgcolor="{$attributes-color}">
-          <font color="#ffffff">Action Item</font>
-        </th>
-        <th width="25%" bgcolor="{$attributes-color}">
-          <font color="#ffffff">Volunteers</font>
-        </th>
-        <xsl:for-each select="item">
-        <tr>
-          <td align="left" valign="center">
-            <xsl:value-of select="@priority"/>
-          </td>
-          <td align="left" valign="center">
-            <xsl:apply-templates/>
-          </td>
-          <td align="left" valign="center">
-            <xsl:value-of select="@owner"/>
-          </td>
-        </tr>
-        </xsl:for-each>
-      </tr>
-    </table>
-  </xsl:template>
-
-  <!-- Link to a bug report -->
-  <xsl:template match="bug">
-      <xsl:variable name="link"><xsl:value-of select="$buglink"/><xsl:value-of select="text()"/></xsl:variable>
-      <a href="{$link}"><xsl:apply-templates/></a>
-  </xsl:template>
-
-  <!-- Process everything else by just passing it through -->
-  <xsl:template match="*|@*">
-    <xsl:copy>
-      <xsl:apply-templates select="@*|*|text()"/>
-    </xsl:copy>
-  </xsl:template>
-
-</xsl:stylesheet>
diff --git a/webapps/host-manager/META-INF/context.xml b/webapps/host-manager/META-INF/context.xml
index 1019dc4..3390e96 100644
--- a/webapps/host-manager/META-INF/context.xml
+++ b/webapps/host-manager/META-INF/context.xml
@@ -22,6 +22,6 @@
   -->
   <!--
   <Valve className="org.apache.catalina.valves.RemoteAddrValve"
-         allow="127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|::1" />
+         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
   -->
 </Context>
\ No newline at end of file
diff --git a/webapps/manager/META-INF/context.xml b/webapps/manager/META-INF/context.xml
index 99276a2..21d9bac 100644
--- a/webapps/manager/META-INF/context.xml
+++ b/webapps/manager/META-INF/context.xml
@@ -22,6 +22,6 @@
   -->
   <!--
   <Valve className="org.apache.catalina.valves.RemoteAddrValve"
-         allow="127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|::1" />
+         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
   -->
 </Context>

-- 
tomcat7: Servlet and JSP engine



More information about the pkg-java-commits mailing list