[SCM] tomcat7: Servlet and JSP engine branch, upstream, updated. upstream/7.0.28-1-gb7a9452

tony mancill tmancill at debian.org
Sat Dec 8 07:44:52 UTC 2012


The following commit has been merged in the upstream branch:
commit b7a945236b2a1c9a6535b97c08c6e1018247f3ac
Author: tony mancill <tmancill at debian.org>
Date:   Sat Dec 1 19:01:45 2012 -0800

    Imported Upstream version 7.0.33

diff --git a/BUILDING.txt b/BUILDING.txt
index d26bd74..efbef9f 100644
--- a/BUILDING.txt
+++ b/BUILDING.txt
@@ -15,7 +15,7 @@
   limitations under the License.
 ================================================================================
 
-$Id: BUILDING.txt 1348360 2012-06-09 11:17:55Z kkolinko $
+$Id: BUILDING.txt 1371983 2012-08-11 17:23:27Z kkolinko $
 
             ====================================================
             Building The Apache Tomcat @VERSION_MAJOR_MINOR@ Servlet/JSP Container
@@ -37,10 +37,32 @@ source distribution, do the following:
 
  1. If the JDK is already installed, skip to (2).
 
- 2. Download a Java Development Kit (JDK) release (version 1.6.x or later)
-    from:
+ 2. Download a version 6 of Java Development Kit (JDK) release (use the
+    latest update available for your chosen version) from
 
         http://www.oracle.com/technetwork/java/javase/downloads/index.html
+        or from another JDK vendor.
+
+    Note regarding later versions of Java:
+
+      As documented elsewhere, one of components in Apache Tomcat includes
+      a private copy of the Apache Commons DBCP library. The source code
+      for this library is downloaded, processed by the build script
+      (renaming the packages) and compiled.
+
+      Due to changes in JDBC interfaces implemented by the library between
+      versions of Java SE specification, the library has to target specific
+      version of Java and can be compiled only with the JDK version
+      implementing this version of specification.
+
+      See Apache Commons DBCP project web site for more details on
+      available versions of the library and its requirements,
+
+        http://commons.apache.org/dbcp/
+
+      If you really want to use a later version of JDK to build Tomcat,
+      several workarounds are possible. One of them is to skip building
+      the component (tomcat-dbcp.jar).
 
  3. Install the JDK according to the instructions included with the release.
 
@@ -325,16 +347,17 @@ To enable Checkstyle, add the following property to build.properties file:
 Once Checkstyle is enabled, the check will be performed automatically
 during the build. The check is run before compilation of the source code.
 
-It is possible to run the check separately. The command is:
-
-    cd ${tomcat.source}
-    ant validate
-
 To speed-up repeated runs of this check, a cache is configured. The cache
 is located in the following directory:
 
     output/res/checkstyle
 
+It is possible to run the check separately by invoking the "validate"
+target. The command is:
+
+    cd ${tomcat.source}
+    ant -Dexecute.validate=true validate
+
 
 (8.2) End-of-line conventions check
 
diff --git a/bin/catalina-tasks.xml b/bin/catalina-tasks.xml
index a40314a..ab40e7c 100644
--- a/bin/catalina-tasks.xml
+++ b/bin/catalina-tasks.xml
@@ -25,7 +25,7 @@
   <!-- set catalina.home if it's not already set -->
   <dirname property="catalina.home.bin.dir" file="${ant.file.catalina-tasks}"/>
   <property name="catalina.home" value="${catalina.home.bin.dir}/.."/>
-  <taskdef resource="org/apache/catalina/ant/catalina.tasks">
+  <typedef resource="org/apache/catalina/ant/catalina.tasks">
     <classpath>
       <fileset file="${catalina.home}/bin/tomcat-juli.jar"/>
       <fileset file="${catalina.home}/lib/tomcat-api.jar"/>
@@ -38,22 +38,8 @@
       <fileset file="${catalina.home}/lib/catalina-ant.jar"/>
       <fileset file="${catalina.home}/lib/tomcat-coyote.jar"/>
     </classpath>
-  </taskdef>
-  <taskdef resource="org/apache/catalina/ant/jmx/jmxaccessor.tasks">
-    <classpath>
-      <fileset file="${catalina.home}/lib/catalina-ant.jar"/>
-    </classpath>
-  </taskdef>
-  <typedef
-        name="jmxEquals"
-        classname="org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition">
-    <classpath>
-      <fileset file="${catalina.home}/lib/catalina-ant.jar"/>
-    </classpath>
   </typedef>
-  <typedef
-        name="jmxCondition"
-        classname="org.apache.catalina.ant.jmx.JMXAccessorCondition">
+  <typedef resource="org/apache/catalina/ant/jmx/jmxaccessor.tasks">
     <classpath>
       <fileset file="${catalina.home}/lib/catalina-ant.jar"/>
     </classpath>
diff --git a/bin/daemon.sh b/bin/daemon.sh
index cc830ae..9a4640d 100755
--- a/bin/daemon.sh
+++ b/bin/daemon.sh
@@ -228,7 +228,7 @@ case "$1" in
       exit $?
     ;;
     *       )
-      echo "Unkown command: \`$1'"
+      echo "Unknown command: \`$1'"
       echo "Usage: $PROGRAM ( commands ... )"
       echo "commands:"
       echo "  run               Start Tomcat without detaching from console"
diff --git a/build.properties.default b/build.properties.default
index 7d31128..8d078c8 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 1350468 2012-06-15 06:11:47Z markt $
+# $Id: build.properties.default 1410718 2012-11-17 10:16:22Z markt $
 # -----------------------------------------------------------------------------
 
 # ----- Version Control Flags -----
 version.major=7
 version.minor=0
-version.build=28
+version.build=33
 version.patch=0
 version.suffix=
 
@@ -182,7 +182,7 @@ junit.jar=${junit.lib}/junit-4.8.2.jar
 junit.loc=http://cloud.github.com/downloads/KentBeck/junit/junit4.8.2.zip
 
 # ----- Checkstyle, version 5.1 or later -----
-checkstyle.version=5.5
+checkstyle.version=5.6
 checkstyle.home=${base.path}/checkstyle-${checkstyle.version}
 checkstyle.loc=${base-sf.loc}/checkstyle/checkstyle-${checkstyle.version}-bin.zip
 checkstyle.jar=${checkstyle.home}/checkstyle-${checkstyle.version}-all.jar
diff --git a/build.xml b/build.xml
index 3ff8f81..169f92d 100644
--- a/build.xml
+++ b/build.xml
@@ -226,6 +226,7 @@
     <include name="**/*.license"/>
     <include name="**/*.manifest"/>
     <include name="**/*.mdl"/>
+    <include name="**/*.MF"/>
     <include name="**/*.notice"/>
     <include name="**/*.nsi"/>
     <include name="**/*.pl"/>
@@ -461,7 +462,6 @@
         <!-- Exclude auto-generated files -->
         <exclude name="java/org/apache/el/parser/ELParser*.java" />
         <exclude name="java/org/apache/el/parser/Node.java" />
-        <exclude name="java/org/apache/tomcat/util/http/parser/HttpParser*.java" />
         <exclude name="java/org/apache/**/parser/JJT*ParserState.java" />
         <exclude name="java/org/apache/**/parser/ParseException.java" />
         <exclude name="java/org/apache/**/parser/SimpleCharStream.java" />
@@ -470,11 +470,12 @@
         <exclude name="**/org/apache/tomcat/dbcp/**"/>
         <exclude name="**/tomcat-deps/**"/>
         <!-- Exclude simple test files -->
-        <exclude name="test/webapp-3.0/bug53257/*.txt"/>
+        <exclude name="test/webapp-3.0/bug53257/**/*.txt"/>
         <exclude name="test/webapp-3.0-fragments/WEB-INF/classes/*.txt"/>
       </fileset>
       <fileset dir="modules/jdbc-pool" >
         <exclude name=".*/**"/>
+        <exclude name="**/MANIFEST.MF"/>
         <patternset refid="text.files" />
       </fileset>
     </checkstyle>
@@ -1692,7 +1693,7 @@ Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform.
 
   </target>
 
-  <target name="dist-source">
+  <target name="dist-source" depends="compile-prepare">
 
     <mkdir dir="${tomcat.dist}/src"/>
 
@@ -1703,6 +1704,7 @@ Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform.
           <or>
             <filename name="**/.settings/**" />
             <filename name="**/.classpath"/>
+            <filename name="**/.checkstyle"/>
             <filename name="**/.project"/>
             <filename name="**/output/**"/>
             <!-- Commented out, because
@@ -1715,12 +1717,15 @@ Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform.
             <filename name="**/*.iml" />
             <filename name="**/*.asc" />
             <filename name="**/*.tmp" />
+            <filename name="**/*.jj" />
             <filename name="**/maven-ant-tasks-*.jar" />
             <filename name="**/thumbs.db" />
             <filename name="**/Thumbs.db" />
             <filename name="*.launch"/>
             <filename name="bin/setenv.*" />
+            <filename name="java/org/apache/catalina/startup/catalina.properties" />
             <filename name="logs/**" />
+            <filename name="webapps/docs/jdbc-pool.xml" />
             <filename name="work/**" />
             <filename name="modules/jdbc-pool/bin/**" />
             <filename name="modules/jdbc-pool/includes/**" />
diff --git a/conf/catalina.properties b/conf/catalina.properties
index bdc1347..42c62d1 100644
--- a/conf/catalina.properties
+++ b/conf/catalina.properties
@@ -73,8 +73,12 @@ server.loader=
 # starting with file:.
 shared.loader=
 
-# List of JAR files that should not be scanned for configuration information
-# such as web fragments, TLD files etc. It must be a comma separated list of
+# List of JAR files that should not be scanned using the JarScanner
+# functionality. This is typically used to scan JARs for configuration
+# information. JARs that do not contain such information may be excluded from
+# the scan to speed up the scanning process. This is the default list. JARs on
+# this list are excluded from all scans. Scan specific lists (to exclude JARs
+# from individual scans) follow this. The list must be a comma separated list of
 # JAR file names.
 # The JARs listed below include:
 # - Tomcat Bootstrap JARs
@@ -84,6 +88,7 @@ shared.loader=
 # - Tomcat JARs
 # - Common non-Tomcat JARs
 # - Sun JDK JARs
+# - OpenJDK JARs
 # - Apple JDK JARs
 tomcat.util.scan.DefaultJarScanner.jarsToSkip=\
 bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\
@@ -104,14 +109,25 @@ geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,\
 ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,\
 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,\
+access-bridge.jar,access-bridge-64.jar,dnsns.jar,jaccess.jar,ldapsec.jar,localedata.jar,\
+sunjce_provider.jar,sunmscapi.jar,sunpkcs11.jar,jhall.jar,tools.jar,\
 sunec.jar,zipfs.jar,\
+gnome-java-bridge.jar,pulse-java.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,\
 junit.jar,junit-*.jar,ant-launcher.jar
 
+# Additional JARs (over and above the default JARs listed above) to skip when
+# scanning for Servlet 3.0 pluggability features. These features include web
+# fragments, annotations, SCIs and classes that match @HandlesTypes. The list
+# must be a comma separated list of JAR file names.
+org.apache.catalina.startup.ContextConfig.jarsToSkip=
+
+# Additional JARs (over and above the default JARs listed above) to skip when
+# scanning for TLDs. The list must be a comma separated list of JAR file names.
+org.apache.catalina.startup.TldConfig.jarsToSkip=
+
 #
 # String cache configuration.
 tomcat.util.buf.StringCache.byte.enabled=true
diff --git a/conf/web.xml b/conf/web.xml
index cc8383c..696101a 100644
--- a/conf/web.xml
+++ b/conf/web.xml
@@ -263,7 +263,7 @@
   <!--   isVirtualWebappRelative                                            -->
   <!--                       Should "virtual" paths be interpreted as       -->
   <!--                       relative to the context root, instead of       -->
-  <!--                       the server root?  (0=false, 1=true) [0]        -->
+  <!--                       the server root? [false]                       -->
   <!--                                                                      -->
   <!--   inputEncoding       The encoding to assume for SSI resources if    -->
   <!--                       one is not available from the resource.        -->
@@ -294,7 +294,7 @@
         </init-param>
         <init-param>
           <param-name>isVirtualWebappRelative</param-name>
-          <param-value>0</param-value>
+          <param-value>false</param-value>
         </init-param>
         <load-on-startup>4</load-on-startup>
     </servlet>
@@ -444,7 +444,7 @@
   <!--   isVirtualWebappRelative                                            -->
   <!--                       Should "virtual" paths be interpreted as       -->
   <!--                       relative to the context root, instead of       -->
-  <!--                       the server root?  (0=false, 1=true) [0]        -->
+  <!--                       the server root? [false]                       -->
   <!--                                                                      -->
   <!--   allowExec           Is use of the exec command enabled? [false]    -->
 
@@ -468,7 +468,7 @@
         </init-param>
         <init-param>
           <param-name>isVirtualWebappRelative</param-name>
-          <param-value>0</param-value>
+          <param-value>false</param-value>
         </init-param>
     </filter>
 -->
@@ -526,6 +526,10 @@
         <mime-type>text/vnd.in3d.3dml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>3ds</extension>
+        <mime-type>image/x-3ds</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>3g2</extension>
         <mime-type>video/3gpp2</mime-type>
     </mime-mapping>
@@ -642,6 +646,10 @@
         <mime-type>application/vnd.android.package-archive</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>appcache</extension>
+        <mime-type>text/cache-manifest</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>application</extension>
         <mime-type>application/x-ms-application</mime-type>
     </mime-mapping>
@@ -650,6 +658,10 @@
         <mime-type>application/vnd.lotus-approach</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>arc</extension>
+        <mime-type>application/x-freearc</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>art</extension>
         <mime-type>image/x-jg</mime-type>
     </mime-mapping>
@@ -758,6 +770,14 @@
         <mime-type>application/octet-stream</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>blb</extension>
+        <mime-type>application/x-blorb</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>blorb</extension>
+        <mime-type>application/x-blorb</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>bmi</extension>
         <mime-type>application/vnd.bmi</mime-type>
     </mime-mapping>
@@ -834,6 +854,10 @@
         <mime-type>application/vnd.ms-cab-compressed</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>caf</extension>
+        <mime-type>audio/x-caf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>cap</extension>
         <mime-type>application/vnd.tcpdump.pcap</mime-type>
     </mime-mapping>
@@ -846,6 +870,26 @@
         <mime-type>application/vnd.ms-pki.seccat</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>cb7</extension>
+        <mime-type>application/x-cbr</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>cba</extension>
+        <mime-type>application/x-cbr</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>cbr</extension>
+        <mime-type>application/x-cbr</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>cbt</extension>
+        <mime-type>application/x-cbr</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>cbz</extension>
+        <mime-type>application/x-cbr</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>cc</extension>
         <mime-type>text/x-c</mime-type>
     </mime-mapping>
@@ -906,6 +950,10 @@
         <mime-type>application/pkix-cert</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>cfs</extension>
+        <mime-type>application/x-cfs-compressed</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>cgm</extension>
         <mime-type>image/cgm</mime-type>
     </mime-mapping>
@@ -1078,6 +1126,10 @@
         <mime-type>application/vnd.mobius.daf</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>dart</extension>
+        <mime-type>application/vnd.dart</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>dataless</extension>
         <mime-type>application/vnd.fdsn.seed</mime-type>
     </mime-mapping>
@@ -1086,6 +1138,10 @@
         <mime-type>application/davmount+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>dbk</extension>
+        <mime-type>application/docbook+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>dcr</extension>
         <mime-type>application/x-director</mime-type>
     </mime-mapping>
@@ -1122,6 +1178,10 @@
         <mime-type>application/vnd.dreamfactory</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>dgc</extension>
+        <mime-type>application/x-dgc-compressed</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>dib</extension>
         <mime-type>image/bmp</mime-type>
     </mime-mapping>
@@ -1159,7 +1219,7 @@
     </mime-mapping>
     <mime-mapping>
         <extension>dmg</extension>
-        <mime-type>application/octet-stream</mime-type>
+        <mime-type>application/x-apple-diskimage</mime-type>
     </mime-mapping>
     <mime-mapping>
         <extension>dmp</extension>
@@ -1306,6 +1366,10 @@
         <mime-type>application/octet-stream</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>emf</extension>
+        <mime-type>application/x-msmetafile</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>eml</extension>
         <mime-type>message/rfc822</mime-type>
     </mime-mapping>
@@ -1314,6 +1378,10 @@
         <mime-type>application/emma+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>emz</extension>
+        <mime-type>application/x-msmetafile</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>eol</extension>
         <mime-type>audio/vnd.digital-winds</mime-type>
     </mime-mapping>
@@ -1334,6 +1402,10 @@
         <mime-type>application/vnd.eszigno3+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>esa</extension>
+        <mime-type>application/vnd.osgi.subsystem</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>esf</extension>
         <mime-type>application/vnd.epson.esf</mime-type>
     </mime-mapping>
@@ -1346,6 +1418,14 @@
         <mime-type>text/x-setext</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>eva</extension>
+        <mime-type>application/x-eva</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>evy</extension>
+        <mime-type>application/x-envoy</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>exe</extension>
         <mime-type>application/octet-stream</mime-type>
     </mime-mapping>
@@ -1390,6 +1470,10 @@
         <mime-type>image/vnd.fastbidsheet</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>fcdt</extension>
+        <mime-type>application/vnd.adobe.formscentral.fcdt</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>fcs</extension>
         <mime-type>application/vnd.isac.fcs</mime-type>
     </mime-mapping>
@@ -1530,10 +1614,18 @@
         <mime-type>application/vnd.groove-account</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>gam</extension>
+        <mime-type>application/x-tads</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>gbr</extension>
         <mime-type>application/rpki-ghostbusters</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>gca</extension>
+        <mime-type>application/x-gca-compressed</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>gdl</extension>
         <mime-type>model/vnd.gdl</mime-type>
     </mime-mapping>
@@ -1566,6 +1658,10 @@
         <mime-type>application/vnd.groove-identity-message</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>gml</extension>
+        <mime-type>application/gml+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>gmx</extension>
         <mime-type>application/vnd.gmx</mime-type>
     </mime-mapping>
@@ -1578,6 +1674,10 @@
         <mime-type>application/vnd.flographit</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>gpx</extension>
+        <mime-type>application/gpx+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>gqf</extension>
         <mime-type>application/vnd.grafeq</mime-type>
     </mime-mapping>
@@ -1590,6 +1690,10 @@
         <mime-type>application/srgs</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>gramps</extension>
+        <mime-type>application/x-gramps-xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>gre</extension>
         <mime-type>application/vnd.geometry-explorer</mime-type>
     </mime-mapping>
@@ -1622,6 +1726,10 @@
         <mime-type>text/vnd.graphviz</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>gxf</extension>
+        <mime-type>application/gxf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>gxt</extension>
         <mime-type>application/vnd.geonext</mime-type>
     </mime-mapping>
@@ -1790,6 +1898,10 @@
         <mime-type>application/inkml+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>install</extension>
+        <mime-type>application/x-install-instructions</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>iota</extension>
         <mime-type>application/vnd.astraea-software.iota</mime-type>
     </mime-mapping>
@@ -1811,7 +1923,7 @@
     </mime-mapping>
     <mime-mapping>
         <extension>iso</extension>
-        <mime-type>application/octet-stream</mime-type>
+        <mime-type>application/x-iso9660-image</mime-type>
     </mime-mapping>
     <mime-mapping>
         <extension>itp</extension>
@@ -1894,6 +2006,10 @@
         <mime-type>application/json</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>jsonml</extension>
+        <mime-type>application/jsonml+json</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>jspf</extension>
         <mime-type>text/plain</mime-type>
     </mime-mapping>
@@ -1942,6 +2058,10 @@
         <mime-type>application/vnd.kde.kpresenter</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>kpxx</extension>
+        <mime-type>application/vnd.ds-keypoint</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>ksp</extension>
         <mime-type>application/vnd.kde.kspread</mime-type>
     </mime-mapping>
@@ -1987,7 +2107,7 @@
     </mime-mapping>
     <mime-mapping>
         <extension>lha</extension>
-        <mime-type>application/octet-stream</mime-type>
+        <mime-type>application/x-lzh-compressed</mime-type>
     </mime-mapping>
     <mime-mapping>
         <extension>link66</extension>
@@ -2006,6 +2126,10 @@
         <mime-type>application/vnd.ibm.modcap</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>lnk</extension>
+        <mime-type>application/x-ms-shortcut</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>log</extension>
         <mime-type>text/plain</mime-type>
     </mime-mapping>
@@ -2035,7 +2159,7 @@
     </mime-mapping>
     <mime-mapping>
         <extension>lzh</extension>
-        <mime-type>application/octet-stream</mime-type>
+        <mime-type>application/x-lzh-compressed</mime-type>
     </mime-mapping>
     <mime-mapping>
         <extension>m13</extension>
@@ -2118,6 +2242,10 @@
         <mime-type>text/troff</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>mar</extension>
+        <mime-type>application/octet-stream</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>mathml</extension>
         <mime-type>application/mathml+xml</mime-type>
     </mime-mapping>
@@ -2166,6 +2294,10 @@
         <mime-type>application/metalink4+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>metalink</extension>
+        <mime-type>application/metalink+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>mets</extension>
         <mime-type>application/mets+xml</mime-type>
     </mime-mapping>
@@ -2194,6 +2326,10 @@
         <mime-type>audio/midi</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>mie</extension>
+        <mime-type>application/x-mie</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>mif</extension>
         <mime-type>application/x-mif</mime-type>
     </mime-mapping>
@@ -2210,6 +2346,22 @@
         <mime-type>video/mj2</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>mk3d</extension>
+        <mime-type>video/x-matroska</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mka</extension>
+        <mime-type>audio/x-matroska</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mks</extension>
+        <mime-type>video/x-matroska</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mkv</extension>
+        <mime-type>video/x-matroska</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>mlp</extension>
         <mime-type>application/vnd.dolby.mlp</mime-type>
     </mime-mapping>
@@ -2226,6 +2378,10 @@
         <mime-type>image/vnd.fujixerox.edmics-mmr</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>mng</extension>
+        <mime-type>video/x-mng</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>mny</extension>
         <mime-type>application/x-msmoney</mime-type>
     </mime-mapping>
@@ -2454,10 +2610,18 @@
         <mime-type>application/x-dtbncx+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>nfo</extension>
+        <mime-type>text/x-nfo</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>ngdat</extension>
         <mime-type>application/vnd.nokia.n-gage.data</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>nitf</extension>
+        <mime-type>application/vnd.nitf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>nlu</extension>
         <mime-type>application/vnd.neurolanguage.nlu</mime-type>
     </mime-mapping>
@@ -2482,10 +2646,22 @@
         <mime-type>image/vnd.net-fpx</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>nsc</extension>
+        <mime-type>application/x-conference</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>nsf</extension>
         <mime-type>application/vnd.lotus-notes</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>ntf</extension>
+        <mime-type>application/vnd.nitf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>nzb</extension>
+        <mime-type>application/x-nzb</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>oa2</extension>
         <mime-type>application/vnd.fujitsu.oasys2</mime-type>
     </mime-mapping>
@@ -2502,6 +2678,10 @@
         <mime-type>application/x-msbinder</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>obj</extension>
+        <mime-type>application/x-tgif</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>oda</extension>
         <mime-type>application/oda</mime-type>
     </mime-mapping>
@@ -2572,6 +2752,10 @@
         <mime-type>application/ogg</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>omdoc</extension>
+        <mime-type>application/omdoc+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>onepkg</extension>
         <mime-type>application/onenote</mime-type>
     </mime-mapping>
@@ -2592,6 +2776,10 @@
         <mime-type>application/oebps-package+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>opml</extension>
+        <mime-type>text/x-opml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>oprc</extension>
         <mime-type>application/vnd.palm</mime-type>
     </mime-mapping>
@@ -3037,6 +3225,10 @@
         <mime-type>audio/vnd.rip</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>ris</extension>
+        <mime-type>application/x-research-info-systems</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>rl</extension>
         <mime-type>application/resource-lists+xml</mime-type>
     </mime-mapping>
@@ -3065,6 +3257,10 @@
         <mime-type>application/vnd.jcp.javame.midlet-rms</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>rmvb</extension>
+        <mime-type>application/vnd.rn-realmedia-vbr</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>rnc</extension>
         <mime-type>application/relax-ng-compact-syntax</mime-type>
     </mime-mapping>
@@ -3117,6 +3313,10 @@
         <mime-type>text/x-asm</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>s3m</extension>
+        <mime-type>audio/s3m</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>saf</extension>
         <mime-type>application/vnd.yamaha.smaf-audio</mime-type>
     </mime-mapping>
@@ -3217,6 +3417,14 @@
         <mime-type>application/vnd.spotfire.sfs</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>sfv</extension>
+        <mime-type>text/x-sfv</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>sgi</extension>
+        <mime-type>image/sgi</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>sgl</extension>
         <mime-type>application/vnd.stardivision.writer-global</mime-type>
     </mime-mapping>
@@ -3247,10 +3455,18 @@
     </mime-mapping>
     -->
     <mime-mapping>
+        <extension>sid</extension>
+        <mime-type>image/x-mrsid-image</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>sig</extension>
         <mime-type>application/pgp-signature</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>sil</extension>
+        <mime-type>audio/silk</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>silo</extension>
         <mime-type>model/mesh</mime-type>
     </mime-mapping>
@@ -3315,6 +3531,10 @@
         <mime-type>application/smil+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>smv</extension>
+        <mime-type>video/x-smv</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>smzip</extension>
         <mime-type>application/vnd.stepmania.package</mime-type>
     </mime-mapping>
@@ -3359,10 +3579,18 @@
         <mime-type>audio/ogg</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>sql</extension>
+        <mime-type>application/x-sql</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>src</extension>
         <mime-type>application/x-wais-source</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>srt</extension>
+        <mime-type>application/x-subrip</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>sru</extension>
         <mime-type>application/sru+xml</mime-type>
     </mime-mapping>
@@ -3371,6 +3599,10 @@
         <mime-type>application/sparql-results+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>ssdl</extension>
+        <mime-type>application/ssdl+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>sse</extension>
         <mime-type>application/vnd.kodak-descriptor</mime-type>
     </mime-mapping>
@@ -3495,6 +3727,10 @@
         <mime-type>text/troff</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>t3</extension>
+        <mime-type>application/x-t3vm-image</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>taglet</extension>
         <mime-type>application/vnd.mynfc</mime-type>
     </mime-mapping>
@@ -3551,6 +3787,10 @@
         <mime-type>application/x-tex-tfm</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>tga</extension>
+        <mime-type>image/x-tga</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>thmx</extension>
         <mime-type>application/vnd.ms-officetheme</mime-type>
     </mime-mapping>
@@ -3651,6 +3891,10 @@
         <mime-type>audio/basic</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>ulx</extension>
+        <mime-type>application/x-glulx</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>umj</extension>
         <mime-type>application/vnd.umajin</mime-type>
     </mime-mapping>
@@ -3831,6 +4075,10 @@
         <mime-type>video/vnd.vivo</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>vob</extension>
+        <mime-type>video/x-ms-vob</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>vor</extension>
         <mime-type>application/vnd.stardivision.writer</mime-type>
     </mime-mapping>
@@ -3908,6 +4156,10 @@
         <mime-type>application/vnd.ms-works</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>wdp</extension>
+        <mime-type>image/vnd.ms-photo</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>weba</extension>
         <mime-type>audio/webm</mime-type>
     </mime-mapping>
@@ -3977,7 +4229,7 @@
     </mime-mapping>
     <mime-mapping>
         <extension>wmz</extension>
-        <mime-type>application/x-ms-wmz</mime-type>
+        <mime-type>application/x-msmetafile</mime-type>
     </mime-mapping>
     <mime-mapping>
         <extension>woff</extension>
@@ -4029,7 +4281,31 @@
     </mime-mapping>
     <mime-mapping>
         <extension>x3d</extension>
-        <mime-type>application/vnd.hzn-3d-crossword</mime-type>
+        <mime-type>model/x3d+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>x3db</extension>
+        <mime-type>model/x3d+binary</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>x3dbz</extension>
+        <mime-type>model/x3d+binary</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>x3dv</extension>
+        <mime-type>model/x3d+vrml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>x3dvz</extension>
+        <mime-type>model/x3d+vrml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>x3dz</extension>
+        <mime-type>model/x3d+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xaml</extension>
+        <mime-type>application/xaml+xml</mime-type>
     </mime-mapping>
     <mime-mapping>
         <extension>xap</extension>
@@ -4116,6 +4392,10 @@
         <mime-type>application/vnd.ms-excel</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>xlf</extension>
+        <mime-type>application/x-xliff+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>xlm</extension>
         <mime-type>application/vnd.ms-excel</mime-type>
     </mime-mapping>
@@ -4152,6 +4432,10 @@
         <mime-type>application/vnd.ms-excel</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>xm</extension>
+        <mime-type>audio/xm</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>xml</extension>
         <mime-type>application/xml</mime-type>
     </mime-mapping>
@@ -4168,6 +4452,10 @@
         <mime-type>application/x-xpinstall</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>xpl</extension>
+        <mime-type>application/xproc+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>xpm</extension>
         <mime-type>image/x-xpixmap</mime-type>
     </mime-mapping>
@@ -4224,6 +4512,10 @@
         <mime-type>chemical/x-xyz</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>xz</extension>
+        <mime-type>application/x-xz</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>yang</extension>
         <mime-type>application/yang</mime-type>
     </mime-mapping>
@@ -4240,6 +4532,38 @@
         <mime-type>application/x-compress</mime-type>
     </mime-mapping>
     <mime-mapping>
+        <extension>z1</extension>
+        <mime-type>application/x-zmachine</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>z2</extension>
+        <mime-type>application/x-zmachine</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>z3</extension>
+        <mime-type>application/x-zmachine</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>z4</extension>
+        <mime-type>application/x-zmachine</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>z5</extension>
+        <mime-type>application/x-zmachine</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>z6</extension>
+        <mime-type>application/x-zmachine</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>z7</extension>
+        <mime-type>application/x-zmachine</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>z8</extension>
+        <mime-type>application/x-zmachine</mime-type>
+    </mime-mapping>
+    <mime-mapping>
         <extension>zaz</extension>
         <mime-type>application/vnd.zzazz.deck+xml</mime-type>
     </mime-mapping>
diff --git a/java/javax/el/BeanELResolver.java b/java/javax/el/BeanELResolver.java
index f4c3394..93371d2 100644
--- a/java/javax/el/BeanELResolver.java
+++ b/java/javax/el/BeanELResolver.java
@@ -292,7 +292,7 @@ public class BeanELResolver extends ELResolver {
                 if (this.write == null) {
                     throw new PropertyNotFoundException(message(ctx,
                             "propertyNotWritable", new Object[] {
-                                    type.getName(), descriptor.getName() }));
+                                    owner.getName(), descriptor.getName() }));
                 }
             }
             return this.write;
@@ -304,7 +304,7 @@ public class BeanELResolver extends ELResolver {
                 if (this.read == null) {
                     throw new PropertyNotFoundException(message(ctx,
                             "propertyNotReadable", new Object[] {
-                                    type.getName(), descriptor.getName() }));
+                                    owner.getName(), descriptor.getName() }));
                 }
             }
             return this.read;
diff --git a/java/javax/servlet/RequestDispatcher.java b/java/javax/servlet/RequestDispatcher.java
index c82693e..bc5ece5 100644
--- a/java/javax/servlet/RequestDispatcher.java
+++ b/java/javax/servlet/RequestDispatcher.java
@@ -39,21 +39,179 @@ import java.io.IOException;
  */
 public interface RequestDispatcher {
 
+    /**
+     * The name of the request attribute that should be set by the container
+     * when custom error-handling servlet or JSP page is invoked. The value of
+     * the attribute is of type {@code java.lang.Throwable}. See the chapter
+     * "Error Handling" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String ERROR_EXCEPTION = "javax.servlet.error.exception";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when custom error-handling servlet or JSP page is invoked. The value of
+     * the attribute is of type {@code java.lang.Class}. See the chapter
+     * "Error Handling" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when custom error-handling servlet or JSP page is invoked. The value of
+     * the attribute is of type {@code java.lang.String}. See the chapter
+     * "Error Handling" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String ERROR_MESSAGE = "javax.servlet.error.message";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when custom error-handling servlet or JSP page is invoked. The value of
+     * the attribute is of type {@code java.lang.String}. See the chapter
+     * "Error Handling" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String ERROR_REQUEST_URI = "javax.servlet.error.request_uri";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when custom error-handling servlet or JSP page is invoked. The value of
+     * the attribute is of type {@code java.lang.String}. See the chapter
+     * "Error Handling" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when custom error-handling servlet or JSP page is invoked. The value of
+     * the attribute is of type {@code java.lang.Integer}. See the chapter
+     * "Error Handling" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #forward(ServletRequest, ServletResponse)} method is
+     * called. It provides the original value of a path-related property of the
+     * request. See the chapter "Forwarded Request Parameters" in the Servlet
+     * Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #forward(ServletRequest, ServletResponse)} method is
+     * called. It provides the original value of a path-related property of the
+     * request. See the chapter "Forwarded Request Parameters" in the Servlet
+     * Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #forward(ServletRequest, ServletResponse)} method is
+     * called. It provides the original value of a path-related property of the
+     * request. See the chapter "Forwarded Request Parameters" in the Servlet
+     * Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #forward(ServletRequest, ServletResponse)} method is
+     * called. It provides the original value of a path-related property of the
+     * request. See the chapter "Forwarded Request Parameters" in the Servlet
+     * Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #forward(ServletRequest, ServletResponse)} method is
+     * called. It provides the original value of a path-related property of the
+     * request. See the chapter "Forwarded Request Parameters" in the Servlet
+     * Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #include(ServletRequest, ServletResponse)} method is
+     * called on the {@code RequestDispatcher} obtained by a path and not by a
+     * name. It provides information on the path that was used to obtain the
+     * {@code RequestDispatcher} instance for this include call. See the chapter
+     * "Included Request Parameters" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #include(ServletRequest, ServletResponse)} method is
+     * called on the {@code RequestDispatcher} obtained by a path and not by a
+     * name. It provides information on the path that was used to obtain the
+     * {@code RequestDispatcher} instance for this include call. See the chapter
+     * "Included Request Parameters" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #include(ServletRequest, ServletResponse)} method is
+     * called on the {@code RequestDispatcher} obtained by a path and not by a
+     * name. It provides information on the path that was used to obtain the
+     * {@code RequestDispatcher} instance for this include call. See the chapter
+     * "Included Request Parameters" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #include(ServletRequest, ServletResponse)} method is
+     * called on the {@code RequestDispatcher} obtained by a path and not by a
+     * name. It provides information on the path that was used to obtain the
+     * {@code RequestDispatcher} instance for this include call. See the chapter
+     * "Included Request Parameters" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
+
+    /**
+     * The name of the request attribute that should be set by the container
+     * when the {@link #include(ServletRequest, ServletResponse)} method is
+     * called on the {@code RequestDispatcher} obtained by a path and not by a
+     * name. It provides information on the path that was used to obtain the
+     * {@code RequestDispatcher} instance for this include call. See the chapter
+     * "Included Request Parameters" in the Servlet Specification for details.
+     *
+     * @since Servlet 3.0
+     */
     public static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
 
     /**
diff --git a/java/javax/servlet/http/Cookie.java b/java/javax/servlet/http/Cookie.java
index 829b242..ba00a37 100644
--- a/java/javax/servlet/http/Cookie.java
+++ b/java/javax/servlet/http/Cookie.java
@@ -50,9 +50,6 @@ import java.util.ResourceBundle;
  * This class supports both the Version 0 (by Netscape) and Version 1 (by RFC
  * 2109) cookie specifications. By default, cookies are created using Version 0
  * to ensure the best interoperability.
- * 
- * @author Various
- * @version $Version$
  */
 public class Cookie implements Cloneable, Serializable {
 
@@ -96,7 +93,7 @@ public class Cookie implements Cloneable, Serializable {
      * By default, cookies are created according to the Netscape cookie
      * specification. The version can be changed with the
      * <code>setVersion</code> method.
-     * 
+     *
      * @param name
      *            a <code>String</code> specifying the name of the cookie
      * @param value
@@ -140,7 +137,7 @@ public class Cookie implements Cloneable, Serializable {
      * Specifies a comment that describes a cookie's purpose. The comment is
      * useful if the browser presents the cookie to the user. Comments are not
      * supported by Netscape Version 0 cookies.
-     * 
+     *
      * @param purpose
      *            a <code>String</code> specifying the comment to display to the
      *            user
@@ -153,7 +150,7 @@ public class Cookie implements Cloneable, Serializable {
     /**
      * Returns the comment describing the purpose of this cookie, or
      * <code>null</code> if the cookie has no comment.
-     * 
+     *
      * @return a <code>String</code> containing the comment, or
      *         <code>null</code> if none
      * @see #setComment
@@ -170,7 +167,7 @@ public class Cookie implements Cloneable, Serializable {
      * visible to servers in a specified Domain Name System (DNS) zone (for
      * example, <code>www.foo.com</code>, but not <code>a.b.foo.com</code>). By
      * default, cookies are only returned to the server that sent them.
-     * 
+     *
      * @param pattern
      *            a <code>String</code> containing the domain name within which
      *            this cookie is visible; form is according to RFC 2109
@@ -183,7 +180,7 @@ public class Cookie implements Cloneable, Serializable {
     /**
      * Returns the domain name set for this cookie. The form of the domain name
      * is set by RFC 2109.
-     * 
+     *
      * @return a <code>String</code> containing the domain name
      * @see #setDomain
      */
@@ -201,7 +198,7 @@ public class Cookie implements Cloneable, Serializable {
      * A negative value means that the cookie is not stored persistently and
      * will be deleted when the Web browser exits. A zero value causes the
      * cookie to be deleted.
-     * 
+     *
      * @param expiry
      *            an integer specifying the maximum age of the cookie in
      *            seconds; if negative, means the cookie is not stored; if zero,
@@ -216,7 +213,7 @@ public class Cookie implements Cloneable, Serializable {
      * Returns the maximum age of the cookie, specified in seconds, By default,
      * <code>-1</code> indicating the cookie will persist until browser
      * shutdown.
-     * 
+     *
      * @return an integer specifying the maximum age of the cookie in seconds; if
      *         negative, means the cookie persists until browser shutdown
      * @see #setMaxAge
@@ -237,7 +234,7 @@ public class Cookie implements Cloneable, Serializable {
      * <p>
      * Consult RFC 2109 (available on the Internet) for more information on
      * setting path names for cookies.
-     * 
+     *
      * @param uri
      *            a <code>String</code> specifying a path
      * @see #getPath
@@ -249,7 +246,7 @@ public class Cookie implements Cloneable, Serializable {
     /**
      * Returns the path on the server to which the browser returns this cookie.
      * The cookie is visible to all subpaths on the server.
-     * 
+     *
      * @return a <code>String</code> specifying a path that contains a servlet
      *         name, for example, <i>/catalog</i>
      * @see #setPath
@@ -263,7 +260,7 @@ public class Cookie implements Cloneable, Serializable {
      * secure protocol, such as HTTPS or SSL.
      * <p>
      * The default value is <code>false</code>.
-     * 
+     *
      * @param flag
      *            if <code>true</code>, sends the cookie from the browser to the
      *            server only when using a secure protocol; if
@@ -278,7 +275,7 @@ public class Cookie implements Cloneable, Serializable {
      * Returns <code>true</code> if the browser is sending cookies only over a
      * secure protocol, or <code>false</code> if the browser can send cookies
      * using any protocol.
-     * 
+     *
      * @return <code>true</code> if the browser uses a secure protocol;
      *         otherwise, <code>true</code>
      * @see #setSecure
@@ -290,7 +287,7 @@ public class Cookie implements Cloneable, Serializable {
     /**
      * Returns the name of the cookie. The name cannot be changed after
      * creation.
-     * 
+     *
      * @return a <code>String</code> specifying the cookie's name
      */
     public String getName() {
@@ -305,7 +302,7 @@ public class Cookie implements Cloneable, Serializable {
      * parentheses, equals signs, commas, double quotes, slashes, question
      * marks, at signs, colons, and semicolons. Empty values may not behave the
      * same way on all browsers.
-     * 
+     *
      * @param newValue
      *            a <code>String</code> specifying the new value
      * @see #getValue
@@ -317,7 +314,7 @@ public class Cookie implements Cloneable, Serializable {
 
     /**
      * Returns the value of the cookie.
-     * 
+     *
      * @return a <code>String</code> containing the cookie's present value
      * @see #setValue
      * @see Cookie
@@ -331,7 +328,7 @@ public class Cookie implements Cloneable, Serializable {
      * complies with RFC 2109, and version 0 complies with the original cookie
      * specification drafted by Netscape. Cookies provided by a browser use and
      * identify the browser's cookie version.
-     * 
+     *
      * @return 0 if the cookie complies with the original Netscape specification;
      *         1 if the cookie complies with RFC 2109
      * @see #setVersion
@@ -347,7 +344,7 @@ public class Cookie implements Cloneable, Serializable {
      * <p>
      * Since RFC 2109 is still somewhat new, consider version 1 as experimental;
      * do not use it yet on production sites.
-     * 
+     *
      * @param v
      *            0 if the cookie should comply with the original Netscape
      *            specification; 1 if the cookie should comply with RFC 2109
@@ -359,7 +356,7 @@ public class Cookie implements Cloneable, Serializable {
 
     // Note -- disabled for now to allow full Netscape compatibility
     // from RFC 2068, token special case characters
-    // 
+    //
     // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
 
     private static final String tspecials = ",; ";
@@ -394,11 +391,13 @@ public class Cookie implements Cloneable, Serializable {
                         "org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
                         "false")).booleanValue();
 
-        String fwdSlashIsSeparator = System.getProperty("org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");
+        String fwdSlashIsSeparator = System.getProperty(
+                "org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");
         if (fwdSlashIsSeparator == null) {
             FWD_SLASH_IS_SEPARATOR = STRICT_SERVLET_COMPLIANCE;
         } else {
-            FWD_SLASH_IS_SEPARATOR = Boolean.valueOf(fwdSlashIsSeparator).booleanValue();
+            FWD_SLASH_IS_SEPARATOR =
+                    Boolean.valueOf(fwdSlashIsSeparator).booleanValue();
         }
 
         if (FWD_SLASH_IS_SEPARATOR) {
@@ -407,7 +406,8 @@ public class Cookie implements Cloneable, Serializable {
             tspecials2 = tspecials2NoSlash;
         }
 
-        String strictNaming = System.getProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING");
+        String strictNaming = System.getProperty(
+                "org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING");
         if (strictNaming == null) {
             STRICT_NAMING = STRICT_SERVLET_COMPLIANCE;
         } else {
@@ -451,18 +451,26 @@ public class Cookie implements Cloneable, Serializable {
     }
 
     /**
-     * @return TODO
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * Sets the flag that controls if this cookie will be hidden from scripts on
+     * the client side.
+     *
+     * @param httpOnly  The new value of the flag
+     *
+     * @since Servlet 3.0
      */
-    public boolean isHttpOnly() {
-        return httpOnly;
+    public void setHttpOnly(boolean httpOnly) {
+        this.httpOnly = httpOnly;
     }
 
     /**
-     * @param httpOnly
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * Gets the flag that controls if this cookie will be hidden from scripts on
+     * the client side.
+     *
+     * @return  <code>true</code> if the cookie is hidden from scripts, else
+     *          <code>false</code>
+     * @since Servlet 3.0
      */
-    public void setHttpOnly(boolean httpOnly) {
-        this.httpOnly = httpOnly;
+    public boolean isHttpOnly() {
+        return httpOnly;
     }
 }
diff --git a/java/javax/servlet/http/HttpServlet.java b/java/javax/servlet/http/HttpServlet.java
index 92ea07d..e3a448f 100644
--- a/java/javax/servlet/http/HttpServlet.java
+++ b/java/javax/servlet/http/HttpServlet.java
@@ -35,7 +35,7 @@ import javax.servlet.ServletResponse;
 /**
  * Provides an abstract class to be subclassed to create
  * an HTTP servlet suitable for a Web site. A subclass of
- * <code>HttpServlet</code> must override at least 
+ * <code>HttpServlet</code> must override at least
  * one method, usually one of these:
  *
  * <ul>
@@ -43,27 +43,27 @@ import javax.servlet.ServletResponse;
  * <li> <code>doPost</code>, for HTTP POST requests
  * <li> <code>doPut</code>, for HTTP PUT requests
  * <li> <code>doDelete</code>, for HTTP DELETE requests
- * <li> <code>init</code> and <code>destroy</code>, 
+ * <li> <code>init</code> and <code>destroy</code>,
  * to manage resources that are held for the life of the servlet
  * <li> <code>getServletInfo</code>, which the servlet uses to
- * provide information about itself 
+ * provide information about itself
  * </ul>
  *
  * <p>There's almost no reason to override the <code>service</code>
  * method. <code>service</code> handles standard HTTP
  * requests by dispatching them to the handler methods
- * for each HTTP request type (the <code>do</code><i>XXX</i>
+ * for each HTTP request type (the <code>do</code><i>Method</i>
  * methods listed above).
  *
- * <p>Likewise, there's almost no reason to override the 
+ * <p>Likewise, there's almost no reason to override the
  * <code>doOptions</code> and <code>doTrace</code> methods.
- * 
+ *
  * <p>Servlets typically run on multithreaded servers,
  * so be aware that a servlet must handle concurrent
  * requests and be careful to synchronize access to shared resources.
  * Shared resources include in-memory data such as
  * instance or class variables and external objects
- * such as files, database connections, and network 
+ * such as files, database connections, and network
  * connections.
  * See the
  * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
@@ -87,24 +87,24 @@ public abstract class HttpServlet extends GenericServlet {
 
     private static final String HEADER_IFMODSINCE = "If-Modified-Since";
     private static final String HEADER_LASTMOD = "Last-Modified";
-    
+
     private static final String LSTRING_FILE =
         "javax.servlet.http.LocalStrings";
     private static ResourceBundle lStrings =
         ResourceBundle.getBundle(LSTRING_FILE);
-   
-    
+
+
     /**
      * Does nothing, because this is an abstract class.
      */
     public HttpServlet() {
         // NOOP
     }
-    
-    
+
+
     /**
      * Called by the server (via the <code>service</code> method) to
-     * allow a servlet to handle a GET request. 
+     * allow a servlet to handle a GET request.
      *
      * <p>Overriding this method to support a GET request also
      * automatically supports an HTTP HEAD request. A HEAD
@@ -112,7 +112,7 @@ public abstract class HttpServlet extends GenericServlet {
      * response, only the request header fields.
      *
      * <p>When overriding this method, read the request data,
-     * write the response headers, get the response's writer or 
+     * write the response headers, get the response's writer or
      * output stream object, and finally, write the response data.
      * It's best to include content type and encoding. When using
      * a <code>PrintWriter</code> object to return the response,
@@ -125,7 +125,7 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * <p>Where possible, set the Content-Length header (with the
      * {@link javax.servlet.ServletResponse#setContentLength} method),
-     * to allow the servlet container to use a persistent connection 
+     * to allow the servlet container to use a persistent connection
      * to return its response to the client, improving performance.
      * The content length is automatically set if the entire response fits
      * inside the response buffer.
@@ -141,10 +141,10 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * <p>The GET method should also be idempotent, meaning
      * that it can be safely repeated. Sometimes making a
-     * method safe also makes it idempotent. For example, 
+     * method safe also makes it idempotent. For example,
      * repeating queries is both safe and idempotent, but
      * buying a product online or modifying data is neither
-     * safe nor idempotent. 
+     * safe nor idempotent.
      *
      * <p>If the request is incorrectly formatted, <code>doGet</code>
      * returns an HTTP "Bad Request" message.
@@ -156,14 +156,14 @@ public abstract class HttpServlet extends GenericServlet {
      * @param resp  an {@link HttpServletResponse} object that
      *                  contains the response the servlet sends
      *                  to the client
-     * 
-     * @exception IOException   if an input or output error is 
+     *
+     * @exception IOException   if an input or output error is
      *                              detected when the servlet handles
      *                              the GET request
      *
      * @exception ServletException  if the request for the GET
      *                                  could not be handled
-     * 
+     *
      * @see javax.servlet.ServletResponse#setContentType
      */
     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
@@ -191,7 +191,7 @@ public abstract class HttpServlet extends GenericServlet {
      * This makes browser and proxy caches work more effectively,
      * reducing the load on server and network resources.
      *
-     * @param req   the <code>HttpServletRequest</code> 
+     * @param req   the <code>HttpServletRequest</code>
      *                  object that is sent to the servlet
      *
      * @return  a <code>long</code> integer specifying
@@ -257,28 +257,28 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * <p>When overriding this method, read the request data,
      * write the response headers, get the response's writer or output
-     * stream object, and finally, write the response data. It's best 
+     * stream object, and finally, write the response data. It's best
      * to include content type and encoding. When using a
-     * <code>PrintWriter</code> object to return the response, set the 
-     * content type before accessing the <code>PrintWriter</code> object. 
+     * <code>PrintWriter</code> object to return the response, set the
+     * content type before accessing the <code>PrintWriter</code> object.
      *
      * <p>The servlet container must write the headers before committing the
-     * response, because in HTTP the headers must be sent before the 
+     * response, because in HTTP the headers must be sent before the
      * response body.
      *
      * <p>Where possible, set the Content-Length header (with the
      * {@link javax.servlet.ServletResponse#setContentLength} method),
-     * to allow the servlet container to use a persistent connection 
+     * to allow the servlet container to use a persistent connection
      * to return its response to the client, improving performance.
      * The content length is automatically set if the entire response fits
-     * inside the response buffer.  
+     * inside the response buffer.
      *
      * <p>When using HTTP 1.1 chunked encoding (which means that the response
-     * has a Transfer-Encoding header), do not set the Content-Length header. 
+     * has a Transfer-Encoding header), do not set the Content-Length header.
      *
      * <p>This method does not need to be either safe or idempotent.
      * Operations requested through POST can have side effects for
-     * which the user can be held accountable, for example, 
+     * which the user can be held accountable, for example,
      * updating stored data or buying items online.
      *
      * <p>If the HTTP POST request is incorrectly formatted,
@@ -292,8 +292,8 @@ public abstract class HttpServlet extends GenericServlet {
      * @param resp  an {@link HttpServletResponse} object that
      *                  contains the response the servlet sends
      *                  to the client
-     * 
-     * @exception IOException   if an input or output error is 
+     *
+     * @exception IOException   if an input or output error is
      *                              detected when the servlet handles
      *                              the request
      *
@@ -320,8 +320,8 @@ public abstract class HttpServlet extends GenericServlet {
      * Called by the server (via the <code>service</code> method)
      * to allow a servlet to handle a PUT request.
      *
-     * The PUT operation allows a client to 
-     * place a file on the server and is similar to 
+     * The PUT operation allows a client to
+     * place a file on the server and is similar to
      * sending a file by FTP.
      *
      * <p>When overriding this method, leave intact
@@ -377,7 +377,7 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * The DELETE operation allows a client to remove a document
      * or Web page from the server.
-     * 
+     *
      * <p>This method does not need to be either safe
      * or idempotent. Operations requested through
      * DELETE can have side effects for which users
@@ -396,7 +396,7 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * @param resp  the {@link HttpServletResponse} object that
      *                  contains the response the servlet returns
-     *                  to the client                                
+     *                  to the client
      *
      * @exception IOException   if an input or output error occurs
      *                              while the servlet is handling the
@@ -417,7 +417,7 @@ public abstract class HttpServlet extends GenericServlet {
             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
         }
     }
-    
+
 
     private static Method[] getAllDeclaredMethods(Class<?> c) {
 
@@ -427,7 +427,7 @@ public abstract class HttpServlet extends GenericServlet {
 
         Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
         Method[] thisMethods = c.getDeclaredMethods();
-        
+
         if ((parentMethods != null) && (parentMethods.length > 0)) {
             Method[] allMethods =
                 new Method[parentMethods.length + thisMethods.length];
@@ -447,7 +447,7 @@ public abstract class HttpServlet extends GenericServlet {
      * Called by the server (via the <code>service</code> method)
      * to allow a servlet to handle a OPTIONS request.
      *
-     * The OPTIONS request determines which HTTP methods 
+     * The OPTIONS request determines which HTTP methods
      * the server supports and
      * returns an appropriate header. For example, if a servlet
      * overrides <code>doGet</code>, this method returns the
@@ -456,7 +456,7 @@ public abstract class HttpServlet extends GenericServlet {
      * <p><code>Allow: GET, HEAD, TRACE, OPTIONS</code>
      *
      * <p>There's no need to override this method unless the
-     * servlet implements new HTTP methods, beyond those 
+     * servlet implements new HTTP methods, beyond those
      * implemented by HTTP 1.1.
      *
      * @param req   the {@link HttpServletRequest} object that
@@ -465,7 +465,7 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * @param resp  the {@link HttpServletResponse} object that
      *                  contains the response the servlet returns
-     *                  to the client                                
+     *                  to the client
      *
      * @exception IOException   if an input or output error occurs
      *                              while the servlet is handling the
@@ -479,7 +479,7 @@ public abstract class HttpServlet extends GenericServlet {
         throws ServletException, IOException {
 
         Method[] methods = getAllDeclaredMethods(this.getClass());
-        
+
         boolean ALLOW_GET = false;
         boolean ALLOW_HEAD = false;
         boolean ALLOW_POST = false;
@@ -487,22 +487,22 @@ public abstract class HttpServlet extends GenericServlet {
         boolean ALLOW_DELETE = false;
         boolean ALLOW_TRACE = true;
         boolean ALLOW_OPTIONS = true;
-        
+
         for (int i=0; i<methods.length; i++) {
             Method m = methods[i];
-            
+
             if (m.getName().equals("doGet")) {
                 ALLOW_GET = true;
                 ALLOW_HEAD = true;
             }
-            if (m.getName().equals("doPost")) 
+            if (m.getName().equals("doPost"))
                 ALLOW_POST = true;
             if (m.getName().equals("doPut"))
                 ALLOW_PUT = true;
             if (m.getName().equals("doDelete"))
                 ALLOW_DELETE = true;
         }
-        
+
         String allow = null;
         if (ALLOW_GET)
             allow=METHOD_GET;
@@ -524,18 +524,18 @@ public abstract class HttpServlet extends GenericServlet {
         if (ALLOW_OPTIONS)
             if (allow==null) allow=METHOD_OPTIONS;
             else allow += ", " + METHOD_OPTIONS;
-        
+
         resp.setHeader("Allow", allow);
     }
-    
-    
+
+
     /**
      * Called by the server (via the <code>service</code> method)
      * to allow a servlet to handle a TRACE request.
      *
      * A TRACE returns the headers sent with the TRACE
      * request to the client, so that they can be used in
-     * debugging. There's no need to override this method. 
+     * debugging. There's no need to override this method.
      *
      * @param req   the {@link HttpServletRequest} object that
      *                  contains the request the client made of
@@ -543,7 +543,7 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * @param resp  the {@link HttpServletResponse} object that
      *                  contains the response the servlet returns
-     *                  to the client                                
+     *                  to the client
      *
      * @exception IOException   if an input or output error occurs
      *                              while the servlet is handling the
@@ -552,42 +552,42 @@ public abstract class HttpServlet extends GenericServlet {
      * @exception ServletException  if the request for the
      *                                  TRACE cannot be handled
      */
-    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) 
+    protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
         throws ServletException, IOException
     {
-        
+
         int responseLength;
-        
+
         String CRLF = "\r\n";
         StringBuilder buffer = new StringBuilder("TRACE ").append(req.getRequestURI())
             .append(" ").append(req.getProtocol());
-        
+
         Enumeration<String> reqHeaderEnum = req.getHeaderNames();
-        
+
         while( reqHeaderEnum.hasMoreElements() ) {
             String headerName = reqHeaderEnum.nextElement();
             buffer.append(CRLF).append(headerName).append(": ")
-                .append(req.getHeader(headerName)); 
+                .append(req.getHeader(headerName));
         }
-        
+
         buffer.append(CRLF);
-        
+
         responseLength = buffer.length();
-        
+
         resp.setContentType("message/http");
         resp.setContentLength(responseLength);
         ServletOutputStream out = resp.getOutputStream();
-        out.print(buffer.toString());        
+        out.print(buffer.toString());
         out.close();
         return;
-    }                
+    }
 
 
     /**
      * Receives standard HTTP requests from the public
      * <code>service</code> method and dispatches
-     * them to the <code>do</code><i>XXX</i> methods defined in 
-     * this class. This method is an HTTP-specific version of the 
+     * them to the <code>do</code><i>Method</i> methods defined in
+     * this class. This method is an HTTP-specific version of the
      * {@link javax.servlet.Servlet#service} method. There's no
      * need to override this method.
      *
@@ -597,7 +597,7 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * @param resp  the {@link HttpServletResponse} object that
      *                  contains the response the servlet returns
-     *                  to the client                                
+     *                  to the client
      *
      * @exception IOException   if an input or output error occurs
      *                              while the servlet is handling the
@@ -605,7 +605,7 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * @exception ServletException  if the HTTP request
      *                                  cannot be handled
-     * 
+     *
      * @see javax.servlet.Servlet#service
      */
     protected void service(HttpServletRequest req, HttpServletResponse resp)
@@ -620,7 +620,13 @@ public abstract class HttpServlet extends GenericServlet {
                 // to go through further expensive logic
                 doGet(req, resp);
             } else {
-                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
+                long ifModifiedSince;
+                try {
+                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
+                } catch (IllegalArgumentException iae) {
+                    // Invalid date header - proceed as if none was set
+                    ifModifiedSince = -1;
+                }
                 if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                     // If the servlet mod time is later, call doGet()
                     // Round down to the nearest second for a proper compare
@@ -639,19 +645,19 @@ public abstract class HttpServlet extends GenericServlet {
 
         } else if (method.equals(METHOD_POST)) {
             doPost(req, resp);
-            
+
         } else if (method.equals(METHOD_PUT)) {
-            doPut(req, resp);        
-            
+            doPut(req, resp);
+
         } else if (method.equals(METHOD_DELETE)) {
             doDelete(req, resp);
-            
+
         } else if (method.equals(METHOD_OPTIONS)) {
             doOptions(req,resp);
-            
+
         } else if (method.equals(METHOD_TRACE)) {
             doTrace(req,resp);
-            
+
         } else {
             //
             // Note that this means NO servlet supports whatever
@@ -662,7 +668,7 @@ public abstract class HttpServlet extends GenericServlet {
             Object[] errArgs = new Object[1];
             errArgs[0] = method;
             errMsg = MessageFormat.format(errMsg, errArgs);
-            
+
             resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
         }
     }
@@ -682,20 +688,20 @@ public abstract class HttpServlet extends GenericServlet {
         if (lastModified >= 0)
             resp.setDateHeader(HEADER_LASTMOD, lastModified);
     }
-   
-    
+
+
     /**
      * Dispatches client requests to the protected
      * <code>service</code> method. There's no need to
      * override this method.
-     * 
+     *
      * @param req   the {@link HttpServletRequest} object that
      *                  contains the request the client made of
      *                  the servlet
      *
      * @param res   the {@link HttpServletResponse} object that
      *                  contains the response the servlet returns
-     *                  to the client                                
+     *                  to the client
      *
      * @exception IOException   if an input or output error occurs
      *                              while the servlet is handling the
@@ -703,7 +709,7 @@ public abstract class HttpServlet extends GenericServlet {
      *
      * @exception ServletException  if the HTTP request cannot
      *                                  be handled
-     * 
+     *
      * @see javax.servlet.Servlet#service
      */
     @Override
@@ -712,7 +718,7 @@ public abstract class HttpServlet extends GenericServlet {
 
         HttpServletRequest  request;
         HttpServletResponse response;
-        
+
         try {
             request = (HttpServletRequest) req;
             response = (HttpServletResponse) res;
@@ -758,6 +764,36 @@ class NoBodyResponse extends HttpServletResponseWrapper {
     }
 
     @Override
+    public void setHeader(String name, String value) {
+        super.setHeader(name, value);
+        checkHeader(name);
+    }
+
+    @Override
+    public void addHeader(String name, String value) {
+        super.addHeader(name, value);
+        checkHeader(name);
+    }
+
+    @Override
+    public void setIntHeader(String name, int value) {
+        super.setIntHeader(name, value);
+        checkHeader(name);
+    }
+
+    @Override
+    public void addIntHeader(String name, int value) {
+        super.addIntHeader(name, value);
+        checkHeader(name);
+    }
+
+    private void checkHeader(String name) {
+        if ("content-length".equalsIgnoreCase(name)) {
+            didSetContentLength = true;
+        }
+    }
+
+    @Override
     public ServletOutputStream getOutputStream() throws IOException {
         return noBody;
     }
@@ -779,7 +815,7 @@ class NoBodyResponse extends HttpServletResponseWrapper {
 /*
  * Servlet output stream that gobbles up all its data.
  */
- 
+
 // file private
 class NoBodyOutputStream extends ServletOutputStream {
 
@@ -806,17 +842,22 @@ class NoBodyOutputStream extends ServletOutputStream {
     }
 
     @Override
-    public void write(byte buf[], int offset, int len)
-        throws IOException
-    {
-        if (len >= 0) {
-            contentLength += len;
-        } else {
-            // XXX
-            // isn't this really an IllegalArgumentException?
-            
-            String msg = lStrings.getString("err.io.negativelength");
-            throw new IOException(msg);
+    public void write(byte buf[], int offset, int len) throws IOException {
+        if (buf == null) {
+            throw new NullPointerException(
+                    lStrings.getString("err.io.nullArray"));
+        }
+
+        if (offset < 0 || len < 0 || offset+len > buf.length) {
+            String msg = lStrings.getString("err.io.indexOutOfBounds");
+            Object[] msgArgs = new Object[3];
+            msgArgs[0] = Integer.valueOf(offset);
+            msgArgs[1] = Integer.valueOf(len);
+            msgArgs[2] = Integer.valueOf(buf.length);
+            msg = MessageFormat.format(msg, msgArgs);
+            throw new IndexOutOfBoundsException(msg);
         }
+
+        contentLength += len;
     }
 }
diff --git a/java/javax/servlet/http/HttpServletRequest.java b/java/javax/servlet/http/HttpServletRequest.java
index b1b0a72..8fc5581 100644
--- a/java/javax/servlet/http/HttpServletRequest.java
+++ b/java/javax/servlet/http/HttpServletRequest.java
@@ -29,10 +29,8 @@ import javax.servlet.ServletRequest;
  * information for HTTP servlets.
  * <p>
  * The servlet container creates an <code>HttpServletRequest</code> object and
- * passes it as an argument to the servlet's service methods (<code>doGet</code>, <code>doPost</code>, etc).
- * 
- * @author Various
- * @version $Version$
+ * passes it as an argument to the servlet's service methods
+ * (<code>doGet</code>, <code>doPost</code>, etc).
  */
 public interface HttpServletRequest extends ServletRequest {
 
@@ -310,11 +308,11 @@ public interface HttpServletRequest extends ServletRequest {
      * </table>
      * <p>
      * To reconstruct an URL with a scheme and host, use
-     * {@link HttpUtils#getRequestURL}.
+     * {@link #getRequestURL}.
      * 
      * @return a <code>String</code> containing the part of the URL from the
      *         protocol name up to the query string
-     * @see HttpUtils#getRequestURL
+     * @see #getRequestURL
      */
     public String getRequestURI();
 
@@ -391,7 +389,6 @@ public interface HttpServletRequest extends ServletRequest {
      *         in the current session context; <code>false</code> otherwise
      * @see #getRequestedSessionId
      * @see #getSession
-     * @see HttpSessionContext
      */
     public boolean isRequestedSessionIdValid();
 
@@ -423,32 +420,42 @@ public interface HttpServletRequest extends ServletRequest {
     public boolean isRequestedSessionIdFromUrl();
 
     /**
-     * @param response
-     * @return TODO
-     * @throws IOException
-     * @throws ServletException
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * Triggers the same authentication process as would be triggered if the
+     * request is for a resource that is protected by a security constraint.
+     *
+     * @param response  The response to use to return any authentication
+     *                  challenge
+     * @return <code>true</code> if the user is successfully authenticated and
+     *         <code>false</code> if not
+     *
+     * @since Servlet 3.0
      */
     public boolean authenticate(HttpServletResponse response)
             throws IOException, ServletException;
 
     /**
-     * @param username
-     * @param password
+     * Authenticate the provided user name and password and then associated the
+     * authenticated user with the request.
+     *
+     * @param username  The user name to authenticate
+     * @param password  The password to use to authenticate the user
+     *
      * @throws ServletException
      *             If any of {@link #getRemoteUser()},
      *             {@link #getUserPrincipal()} or {@link #getAuthType()} are
      *             non-null, if the configured authenticator does not support
      *             user name and password authentication or if the
      *             authentication fails
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * @since Servlet 3.0
      */
     public void login(String username, String password) throws ServletException;
 
     /**
+     * Removes any authenticated user from the request.
+     *
      * @throws ServletException
      *             If the logout fails
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * @since Servlet 3.0
      */
     public void logout() throws ServletException;
 
diff --git a/java/javax/servlet/http/HttpServletRequestWrapper.java b/java/javax/servlet/http/HttpServletRequestWrapper.java
index 1d3b329..327529c 100644
--- a/java/javax/servlet/http/HttpServletRequestWrapper.java
+++ b/java/javax/servlet/http/HttpServletRequestWrapper.java
@@ -279,7 +279,13 @@ public class HttpServletRequestWrapper extends ServletRequestWrapper implements
     }
 
     /**
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default behavior of this method is to return
+     * {@link HttpServletRequest#authenticate(HttpServletResponse)}
+     * on the wrapped request object.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public boolean authenticate(HttpServletResponse response)
@@ -288,7 +294,13 @@ public class HttpServletRequestWrapper extends ServletRequestWrapper implements
     }
 
     /**
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default behavior of this method is to return
+     * {@link HttpServletRequest#login(String, String)}
+     * on the wrapped request object.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public void login(String username, String password) throws ServletException {
@@ -296,7 +308,13 @@ public class HttpServletRequestWrapper extends ServletRequestWrapper implements
     }
 
     /**
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default behavior of this method is to return
+     * {@link HttpServletRequest#logout()}
+     * on the wrapped request object.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public void logout() throws ServletException {
@@ -304,7 +322,13 @@ public class HttpServletRequestWrapper extends ServletRequestWrapper implements
     }
 
     /**
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default behavior of this method is to return
+     * {@link HttpServletRequest#getParts()}
+     * on the wrapped request object.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public Collection<Part> getParts() throws IllegalStateException,
@@ -313,10 +337,13 @@ public class HttpServletRequestWrapper extends ServletRequestWrapper implements
     }
 
     /**
-     * @throws ServletException
-     * @throws IOException
-     * @throws IllegalStateException
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default behavior of this method is to return
+     * {@link HttpServletRequest#getPart(String)}
+     * on the wrapped request object.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public Part getPart(String name) throws IllegalStateException, IOException,
diff --git a/java/javax/servlet/http/HttpServletResponse.java b/java/javax/servlet/http/HttpServletResponse.java
index c111a4d..9882fee 100644
--- a/java/javax/servlet/http/HttpServletResponse.java
+++ b/java/javax/servlet/http/HttpServletResponse.java
@@ -29,8 +29,6 @@ import javax.servlet.ServletResponse;
  * The servlet container creates an <code>HttpServletResponse</code> object and
  * passes it as an argument to the servlet's service methods (<code>doGet</code>, <code>doPost</code>, etc).
  * 
- * @author Various
- * @version $Version$
  * @see javax.servlet.ServletResponse
  */
 public interface HttpServletResponse extends ServletResponse {
@@ -301,28 +299,38 @@ public interface HttpServletResponse extends ServletResponse {
     public void setStatus(int sc, String sm);
 
     /**
-     * @return TODO
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * Return the HTTP status code associated with this Response.
+     *
+     * @since Servlet 3.0
      */
     public int getStatus();
 
     /**
-     * @param name
-     * @return TODO
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * Return the value for the specified header, or <code>null</code> if this
+     * header has not been set.  If more than one value was added for this
+     * name, only the first is returned; use {@link #getHeaders(String)} to
+     * retrieve all of them.
+     *
+     * @param name Header name to look up
+     *
+     * @since Servlet 3.0
      */
     public String getHeader(String name);
 
     /**
-     * @param name
-     * @return TODO
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * Return a Collection of all the header values associated with the
+     * specified header name.
+     *
+     * @param name Header name to look up
+     *
+     * @since Servlet 3.0
      */
     public Collection<String> getHeaders(String name);
 
     /**
-     * @return TODO
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * Return an Iterable of all the header names set for this response.
+     *
+     * @since Servlet 3.0
      */
     public Collection<String> getHeaderNames();
 
diff --git a/java/javax/servlet/http/HttpServletResponseWrapper.java b/java/javax/servlet/http/HttpServletResponseWrapper.java
index 5162906..4c57e35 100644
--- a/java/javax/servlet/http/HttpServletResponseWrapper.java
+++ b/java/javax/servlet/http/HttpServletResponseWrapper.java
@@ -215,7 +215,13 @@ public class HttpServletResponseWrapper extends ServletResponseWrapper
     }
 
     /**
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default implementation is to call
+     * {@link HttpServletResponse#getStatus()}
+     * on the wrapper {@link HttpServletResponse}.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public int getStatus() {
@@ -223,7 +229,13 @@ public class HttpServletResponseWrapper extends ServletResponseWrapper
     }
 
     /**
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default implementation is to call
+     * {@link HttpServletResponse#getHeader(String)}
+     * on the wrapper {@link HttpServletResponse}.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public String getHeader(String name) {
@@ -231,7 +243,13 @@ public class HttpServletResponseWrapper extends ServletResponseWrapper
     }
 
     /**
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default implementation is to call
+     * {@link HttpServletResponse#getHeaders(String)}
+     * on the wrapper {@link HttpServletResponse}.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public Collection<String> getHeaders(String name) {
@@ -239,7 +257,13 @@ public class HttpServletResponseWrapper extends ServletResponseWrapper
     }
 
     /**
-     * @since Servlet 3.0 TODO SERVLET3 - Add comments
+     * {@inheritDoc}
+     * <p>
+     * The default implementation is to call
+     * {@link HttpServletResponse#getHeaderNames()}
+     * on the wrapper {@link HttpServletResponse}.
+     *
+     * @since Servlet 3.0
      */
     @Override
     public Collection<String> getHeaderNames() {
diff --git a/java/javax/servlet/http/HttpSession.java b/java/javax/servlet/http/HttpSession.java
index e156df2..ce99b4e 100644
--- a/java/javax/servlet/http/HttpSession.java
+++ b/java/javax/servlet/http/HttpSession.java
@@ -61,10 +61,7 @@ import javax.servlet.ServletContext;
  * <code>ServletContext</code>), so information stored in one context will not
  * be directly visible in another.
  * 
- * @author Various
- * @version $Version$
  * @see HttpSessionBindingListener
- * @see HttpSessionContext
  */
 public interface HttpSession {
 
diff --git a/java/javax/servlet/http/LocalStrings.properties b/java/javax/servlet/http/LocalStrings.properties
index a68b129..a9def62 100644
--- a/java/javax/servlet/http/LocalStrings.properties
+++ b/java/javax/servlet/http/LocalStrings.properties
@@ -18,7 +18,8 @@
 
 err.cookie_name_is_token=Cookie name \"{0}\" is a reserved token
 err.cookie_name_blank=Cookie name may not be null or zero length
-err.io.negativelength=Negative Length given in write method
+err.io.nullArray=Null passed for byte array in write method
+err.io.indexOutOfBounds=Invalid offset [{0}] and / or length [{1}] specified for array of size [{2}]
 err.io.short_read=Short Read
 
 http.method_not_implemented=Method {0} is not is not implemented by this servlet for this URI
diff --git a/java/javax/servlet/jsp/JspException.java b/java/javax/servlet/jsp/JspException.java
index 90f311a..00d4b0e 100644
--- a/java/javax/servlet/jsp/JspException.java
+++ b/java/javax/servlet/jsp/JspException.java
@@ -53,7 +53,7 @@ public class JspException extends Exception {
      * <code>java.lang.Throwable.getCause()</code> and {@link #getRootCause()}
      * methods.
      * 
-     * @see <code>java.lang.Exception.Exception(String, Throwable)</code>
+     * @see java.lang.Exception#Exception(String, Throwable)
      *
      * @param message       a <code>String</code> containing the text of the
      *                      exception message
@@ -74,7 +74,7 @@ public class JspException extends Exception {
      * <code>java.lang.Throwable.getCause()</code> and {@link #getRootCause()}
      * methods.
      * 
-     * @see <code>java.lang.Exception.Exception(Throwable)</code>
+     * @see java.lang.Exception#Exception(Throwable)
      *
      * @param cause         the <code>Throwable</code> exception that
      *                      interfered with the JSP's normal operation, making
diff --git a/java/org/apache/catalina/AsyncDispatcher.java b/java/org/apache/catalina/AsyncDispatcher.java
new file mode 100644
index 0000000..c7f29df
--- /dev/null
+++ b/java/org/apache/catalina/AsyncDispatcher.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+public interface AsyncDispatcher {
+
+    /**
+     * Perform an asynchronous dispatch. The method does not check if the
+     * request is in an appropriate state for this; it is the caller's
+     * responsibility to check this.
+     */
+    public void dispatch(ServletRequest request, ServletResponse response)
+            throws ServletException, IOException;
+}
diff --git a/java/org/apache/catalina/CatalinaFactory.java b/java/org/apache/catalina/CatalinaFactory.java
index 9127d61..cf41033 100644
--- a/java/org/apache/catalina/CatalinaFactory.java
+++ b/java/org/apache/catalina/CatalinaFactory.java
@@ -29,6 +29,7 @@ import org.apache.catalina.core.StandardPipeline;
  * @deprecated There was no demand for this capability and it will be removed in
  *             Tomcat 8.0.x
  */
+ at Deprecated
 public class CatalinaFactory {
 
     private static CatalinaFactory factory = new CatalinaFactory();
diff --git a/java/org/apache/catalina/Context.java b/java/org/apache/catalina/Context.java
index 3eee519..a5cece4 100644
--- a/java/org/apache/catalina/Context.java
+++ b/java/org/apache/catalina/Context.java
@@ -59,7 +59,7 @@ import org.apache.tomcat.util.http.mapper.Mapper;
  * <p>
  *
  * @author Craig R. McClanahan
- * @version $Id: Context.java 1350247 2012-06-14 14:04:20Z markt $
+ * @version $Id: Context.java 1390886 2012-09-27 08:24:49Z markt $
  */
 
 public interface Context extends Container {
@@ -164,7 +164,12 @@ public interface Context extends Container {
 
     /**
      * Return the application available flag for this Context.
+     *
+     * @deprecated  This will be removed in Tomcat 8.0.x onwards. Use
+     *              {@link #getState()}.{@link LifecycleState#isAvailable()
+     *              isAvailable()} instead
      */
+    @Deprecated
     public boolean getAvailable();
 
 
diff --git a/java/org/apache/catalina/DistributedManager.java b/java/org/apache/catalina/DistributedManager.java
index bd9e761..561c488 100644
--- a/java/org/apache/catalina/DistributedManager.java
+++ b/java/org/apache/catalina/DistributedManager.java
@@ -21,11 +21,17 @@ import java.util.Set;
 
 /**
  * Interface implemented by session managers that do not keep a complete copy
- * of all sessions on the local node but do know where every session is. The
- * BackupManager is an example of such a Manager. Sessions can be primary
- * (master copy on this node), backup (backup copy on this node) or proxy (only
- * the session ID on this node). The identity of the primary and backup nodes
- * are known for all sessions, including proxy sessions.
+ * of all sessions in memory but do know where every session is. The
+ * BackupManager is an example of such a Manager as are implementations of the
+ * StoreManager interface.
+ * <p>
+ * With the BackupManager, sessions can be primary (master copy on this node),
+ * backup (backup copy on this node) or proxy (only the session ID on this
+ * node). The identity of the primary and backup nodes are known for all
+ * sessions, including proxy sessions.
+ * <p>
+ * With StoreManager implementations, sessions can be primary (session is in
+ * memory) or proxy (session is in the Store).
  */
 public interface DistributedManager {
 
diff --git a/java/org/apache/catalina/Executor.java b/java/org/apache/catalina/Executor.java
index 0f7d49a..5f323c7 100644
--- a/java/org/apache/catalina/Executor.java
+++ b/java/org/apache/catalina/Executor.java
@@ -31,7 +31,7 @@ public interface Executor extends java.util.concurrent.Executor, Lifecycle {
      * time until it throws a RejectedExecutionException
      *
      * @param command the runnable task
-     * @throws org.apache.catalina.util.RejectedExecutionException if this task
+     * @throws java.util.concurrent.RejectedExecutionException if this task
      * cannot be accepted for execution - the queue is full
      * @throws NullPointerException if command or unit is null
      */
diff --git a/java/org/apache/catalina/Host.java b/java/org/apache/catalina/Host.java
index 55b9fe3..72316bc 100644
--- a/java/org/apache/catalina/Host.java
+++ b/java/org/apache/catalina/Host.java
@@ -41,7 +41,7 @@ import java.util.regex.Pattern;
  * of Context (representing an individual servlet context).
  *
  * @author Craig R. McClanahan
- * @version $Id: Host.java 1200159 2011-11-10 05:33:31Z kkolinko $
+ * @version $Id: Host.java 1382367 2012-09-08 21:11:46Z markt $
  */
 
 public interface Host extends Container {
@@ -180,6 +180,22 @@ public interface Host extends Container {
     public ExecutorService getStartStopExecutor();
 
 
+    /**
+     * Returns true of the Host is configured to automatically undeploy old
+     * versions of applications deployed using parallel deployment. This only
+     * takes effect is {@link #getAutoDeploy()} also returns true.
+     */
+    public boolean getUndeployOldVersions();
+
+
+    /**
+     * Set to true if the Host should automatically undeploy old versions of
+     * applications deployed using parallel deployment. This only takes effect
+     * if {@link #getAutoDeploy()} returns true.
+     */
+    public void setUndeployOldVersions(boolean undeployOldVersions);
+
+
     // --------------------------------------------------------- Public Methods
 
     /**
diff --git a/java/org/apache/catalina/ant/antlib.xml b/java/org/apache/catalina/ant/antlib.xml
index 5923ec0..4c36a27 100644
--- a/java/org/apache/catalina/ant/antlib.xml
+++ b/java/org/apache/catalina/ant/antlib.xml
@@ -16,6 +16,7 @@
   limitations under the License.
 -->
 <antlib>
+  <!-- Pure Catalina tasks -->
   <typedef
         name="list"
         classname="org.apache.catalina.ant.ListTask" />
@@ -40,9 +41,14 @@
   <typedef
         name="sessions"
         classname="org.apache.catalina.ant.SessionsTask" />
+  <!-- Jk Task -->
+  <typedef
+        name="jkstatus"
+        classname="org.apache.catalina.ant.JKStatusUpdateTask" />
   <typedef
         name="jkupdate"
         classname="org.apache.catalina.ant.JKStatusUpdateTask" />
+  <!-- Manager JMX -->
   <typedef
         name="jmxManagerSet"
         classname="org.apache.catalina.ant.JMXSetTask" />
@@ -52,4 +58,18 @@
   <typedef
         name="jmxManagerQuery"
         classname="org.apache.catalina.ant.JMXQueryTask" />
+  <!-- Other -->
+<!-- These tasks are deliberately omitted here,
+  because they depend on other Tomcat components besides catalina-ant.jar
+  and thus are hard to use with antlib.
+  <typedef
+        name="validator"
+        classname="org.apache.catalina.ant.ValidatorTask" />
+  <typedef
+        name="jasper"
+        classname="org.apache.jasper.JspC" />
+  <typedef
+        name="jasper2"
+        classname="org.apache.jasper.JspC" />
+-->
 </antlib>
\ No newline at end of file
diff --git a/java/org/apache/catalina/ant/catalina.tasks b/java/org/apache/catalina/ant/catalina.tasks
index 119432e..3ebae94 100644
--- a/java/org/apache/catalina/ant/catalina.tasks
+++ b/java/org/apache/catalina/ant/catalina.tasks
@@ -26,6 +26,7 @@ validator=org.apache.catalina.ant.ValidatorTask
 
 #Jk Task
 jkstatus=org.apache.catalina.ant.JKStatusUpdateTask
+jkupdate=org.apache.catalina.ant.JKStatusUpdateTask
 
 # Manager JMX
 jmxManagerSet=org.apache.catalina.ant.JMXSetTask
diff --git a/java/org/apache/catalina/ant/jmx/Arg.java b/java/org/apache/catalina/ant/jmx/Arg.java
index 20d5db1..a03ed61 100644
--- a/java/org/apache/catalina/ant/jmx/Arg.java
+++ b/java/org/apache/catalina/ant/jmx/Arg.java
@@ -14,17 +14,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.catalina.ant.jmx;
 
 /**
  *
  * @author Peter Rossbach
- * @version $Id: Arg.java 939305 2010-04-29 13:43:39Z kkolinko $
+ * @version $Id: Arg.java 1360850 2012-07-12 18:35:57Z markt $
  * @since 5.5.10
  */
 public class Arg {
+    /**
+     * @deprecated  Use getter/setter
+     */
+    @Deprecated
     String type;
+    /**
+     * @deprecated  Use getter/setter
+     */
+    @Deprecated
     String value;
 
     public void setType( String type) {
@@ -33,6 +40,10 @@ public class Arg {
     public void setValue( String value ) {
         this.value=value;
     }
+    /**
+     * @deprecated  Use {@link #setValue(String)}
+     */
+    @Deprecated
     public void addText( String text ) {
         this.value=text;
     }
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
index 1e0ede4..af805d2 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
@@ -55,7 +55,7 @@ import org.apache.tools.ant.BuildException;
  * These tasks require Ant 1.6 or later interface.
  *
  * @author Peter Rossbach
- * @version $Revision: 881567 $
+ * @version $Revision: 1360850 $
  * @since 5.5.12
  */
 public class JMXAccessorCreateTask extends JMXAccessorTask {
@@ -173,8 +173,8 @@ public class JMXAccessorCreateTask extends JMXAccessorTask {
            sigA = new String[args.size()];
            for( int i=0; i<args.size(); i++ ) {
                Arg arg=args.get(i);
-               if( arg.type==null) {
-                   arg.type="java.lang.String";
+               if (arg.getType() == null) {
+                   arg.setType("java.lang.String");
                    sigA[i]=arg.getType();
                    argsA[i]=arg.getValue();
                } else {
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
index 613841c..579f03a 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
@@ -87,7 +87,7 @@ import org.apache.tools.ant.BuildException;
  * These tasks require Ant 1.6 or later interface.
  *
  * @author Peter Rossbach
- * @version $Id: JMXAccessorInvokeTask.java 1060524 2011-01-18 18:38:02Z kkolinko $
+ * @version $Id: JMXAccessorInvokeTask.java 1360850 2012-07-12 18:35:57Z markt $
  * @since 5.5.10
  */
 
@@ -188,8 +188,8 @@ public class JMXAccessorInvokeTask extends JMXAccessorTask {
             String sigA[]=new String[args.size()];
             for( int i=0; i<args.size(); i++ ) {
                 Arg arg=args.get(i);
-                if( arg.type==null) {
-                    arg.type="java.lang.String";
+                if (arg.getType() == null) {
+                    arg.setType("java.lang.String");
                     sigA[i]=arg.getType();
                     argsA[i]=arg.getValue();
                 } else {
diff --git a/java/org/apache/catalina/ant/jmx/jmxaccessor.tasks b/java/org/apache/catalina/ant/jmx/jmxaccessor.tasks
index 573de20..05a2a8f 100644
--- a/java/org/apache/catalina/ant/jmx/jmxaccessor.tasks
+++ b/java/org/apache/catalina/ant/jmx/jmxaccessor.tasks
@@ -21,3 +21,5 @@ jmxInvoke=org.apache.catalina.ant.jmx.JMXAccessorInvokeTask
 jmxQuery=org.apache.catalina.ant.jmx.JMXAccessorQueryTask
 jmxCreate=org.apache.catalina.ant.jmx.JMXAccessorCreateTask
 jmxUnregister=org.apache.catalina.ant.jmx.JMXAccessorUnregisterTask
+jmxEquals=org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition
+jmxCondition=org.apache.catalina.ant.jmx.JMXAccessorCondition
diff --git a/java/org/apache/catalina/authenticator/DigestAuthenticator.java b/java/org/apache/catalina/authenticator/DigestAuthenticator.java
index 55208bb..644d3de 100644
--- a/java/org/apache/catalina/authenticator/DigestAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/DigestAuthenticator.java
@@ -5,9 +5,9 @@
  * 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.
@@ -20,7 +20,7 @@ package org.apache.catalina.authenticator;
 
 
 import java.io.IOException;
-import java.nio.charset.Charset;
+import java.io.StringReader;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
@@ -35,9 +35,12 @@ import org.apache.catalina.LifecycleException;
 import org.apache.catalina.Realm;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.util.ConcurrentMessageDigest;
 import org.apache.catalina.util.MD5Encoder;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.http.parser.HttpParser;
 
 
 
@@ -47,7 +50,7 @@ import org.apache.juli.logging.LogFactory;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: DigestAuthenticator.java 1349321 2012-06-12 13:26:10Z markt $
+ * @version $Id: DigestAuthenticator.java 1405416 2012-11-03 20:55:42Z markt $
  */
 
 public class DigestAuthenticator extends AuthenticatorBase {
@@ -59,7 +62,10 @@ public class DigestAuthenticator extends AuthenticatorBase {
 
     /**
      * The MD5 helper object for this class.
+     *
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     protected static final MD5Encoder md5Encoder = new MD5Encoder();
 
 
@@ -80,12 +86,12 @@ public class DigestAuthenticator extends AuthenticatorBase {
 
     public DigestAuthenticator() {
         super();
+        setCache(false);
         try {
             if (md5Helper == null)
                 md5Helper = MessageDigest.getInstance("MD5");
         } catch (NoSuchAlgorithmException e) {
-            e.printStackTrace();
-            throw new IllegalStateException();
+            throw new IllegalStateException(e);
         }
     }
 
@@ -95,24 +101,32 @@ public class DigestAuthenticator extends AuthenticatorBase {
 
     /**
      * MD5 message digest provider.
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x onwards
      */
+    @Deprecated
     protected static volatile MessageDigest md5Helper;
 
 
     /**
-     * List of client nonce values currently being tracked
+     * List of server nonce values currently being tracked
      */
-    protected Map<String,NonceInfo> cnonces;
+    protected Map<String,NonceInfo> nonces;
 
 
     /**
-     * Maximum number of client nonces to keep in the cache. If not specified,
+     * Maximum number of server nonces to keep in the cache. If not specified,
      * the default value of 1000 is used.
      */
-    protected int cnonceCacheSize = 1000;
+    protected int nonceCacheSize = 1000;
 
 
     /**
+     * The window size to use to track seen nonce count values for a given
+     * nonce. If not specified, the default of 100 is used.
+     */
+    protected int nonceCountWindowSize = 100;
+
+    /**
      * Private key.
      */
     protected String key = null;
@@ -150,13 +164,23 @@ public class DigestAuthenticator extends AuthenticatorBase {
     }
 
 
-    public int getCnonceCacheSize() {
-        return cnonceCacheSize;
+    public int getNonceCountWindowSize() {
+        return nonceCountWindowSize;
+    }
+
+
+    public void setNonceCountWindowSize(int nonceCountWindowSize) {
+        this.nonceCountWindowSize = nonceCountWindowSize;
     }
 
 
-    public void setCnonceCacheSize(int cnonceCacheSize) {
-        this.cnonceCacheSize = cnonceCacheSize;
+    public int getNonceCacheSize() {
+        return nonceCacheSize;
+    }
+
+
+    public void setNonceCacheSize(int nonceCacheSize) {
+        this.nonceCacheSize = nonceCacheSize;
     }
 
 
@@ -263,18 +287,19 @@ public class DigestAuthenticator extends AuthenticatorBase {
         // Validate any credentials already included with this request
         String authorization = request.getHeader("authorization");
         DigestInfo digestInfo = new DigestInfo(getOpaque(), getNonceValidity(),
-                getKey(), cnonces, isValidateUri());
+                getKey(), nonces, isValidateUri());
         if (authorization != null) {
-            if (digestInfo.validate(request, authorization, config)) {
-                principal = digestInfo.authenticate(context.getRealm());
-            }
-            
-            if (principal != null) {
-                String username = parseUsername(authorization);
-                register(request, response, principal,
-                        HttpServletRequest.DIGEST_AUTH,
-                         username, null);
-                return (true);
+            if (digestInfo.parse(request, authorization)) {
+                if (digestInfo.validate(request, config)) {
+                    principal = digestInfo.authenticate(context.getRealm());
+                }
+
+                if (principal != null && !digestInfo.isNonceStale()) {
+                    register(request, response, principal,
+                            HttpServletRequest.DIGEST_AUTH,
+                            digestInfo.getUsername(), null);
+                    return true;
+                }
             }
         }
 
@@ -285,11 +310,9 @@ public class DigestAuthenticator extends AuthenticatorBase {
         String nonce = generateNonce(request);
 
         setAuthenticateHeader(request, response, config, nonce,
-                digestInfo.isNonceStale());
+                principal != null && digestInfo.isNonceStale());
         response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
-        //      hres.flushBuffer();
-        return (false);
-
+        return false;
     }
 
 
@@ -307,7 +330,10 @@ public class DigestAuthenticator extends AuthenticatorBase {
      * can be identified, return <code>null</code>
      *
      * @param authorization Authorization string to be parsed
+     *
+     * @deprecated  Unused. Will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     protected String parseUsername(String authorization) {
 
         // Validate the authorization credentials format
@@ -373,17 +399,20 @@ public class DigestAuthenticator extends AuthenticatorBase {
 
         long currentTime = System.currentTimeMillis();
 
-        
+
         String ipTimeKey =
             request.getRemoteAddr() + ":" + currentTime + ":" + getKey();
 
-        byte[] buffer;
-        synchronized (md5Helper) {
-            buffer = md5Helper.digest(
-                    ipTimeKey.getBytes(Charset.defaultCharset()));
+        byte[] buffer = ConcurrentMessageDigest.digestMD5(
+                ipTimeKey.getBytes(B2CConverter.ISO_8859_1));
+        String nonce = currentTime + ":" + MD5Encoder.encode(buffer);
+
+        NonceInfo info = new NonceInfo(currentTime, getNonceCountWindowSize());
+        synchronized (nonces) {
+            nonces.put(nonce, info);
         }
 
-        return currentTime + ":" + md5Encoder.encode(buffer);
+        return nonce;
     }
 
 
@@ -442,22 +471,22 @@ public class DigestAuthenticator extends AuthenticatorBase {
 
 
     // ------------------------------------------------------- Lifecycle Methods
-    
+
     @Override
     protected synchronized void startInternal() throws LifecycleException {
         super.startInternal();
-        
+
         // Generate a random secret key
         if (getKey() == null) {
             setKey(sessionIdGenerator.generateSessionId());
         }
-        
+
         // Generate the opaque string the same way
         if (getOpaque() == null) {
             setOpaque(sessionIdGenerator.generateSessionId());
         }
-        
-        cnonces = new LinkedHashMap<String, DigestAuthenticator.NonceInfo>() {
+
+        nonces = new LinkedHashMap<String, DigestAuthenticator.NonceInfo>() {
 
             private static final long serialVersionUID = 1L;
             private static final long LOG_SUPPRESS_TIME = 5 * 60 * 1000;
@@ -469,7 +498,7 @@ public class DigestAuthenticator extends AuthenticatorBase {
                     Map.Entry<String,NonceInfo> eldest) {
                 // This is called from a sync so keep it simple
                 long currentTime = System.currentTimeMillis();
-                if (size() > getCnonceCacheSize()) {
+                if (size() > getNonceCacheSize()) {
                     if (lastLog < currentTime &&
                             currentTime - eldest.getValue().getTimestamp() <
                             getNonceValidity()) {
@@ -484,13 +513,13 @@ public class DigestAuthenticator extends AuthenticatorBase {
             }
         };
     }
- 
+
     private static class DigestInfo {
 
-        private String opaque;
-        private long nonceValidity;
-        private String key;
-        private Map<String,NonceInfo> cnonces;
+        private final String opaque;
+        private final long nonceValidity;
+        private final String key;
+        private final Map<String,NonceInfo> nonces;
         private boolean validateUri = true;
 
         private String userName = null;
@@ -502,69 +531,59 @@ public class DigestAuthenticator extends AuthenticatorBase {
         private String cnonce = null;
         private String realmName = null;
         private String qop = null;
+        private String opaqueReceived = null;
 
         private boolean nonceStale = false;
 
 
         public DigestInfo(String opaque, long nonceValidity, String key,
-                Map<String,NonceInfo> cnonces, boolean validateUri) {
+                Map<String,NonceInfo> nonces, boolean validateUri) {
             this.opaque = opaque;
             this.nonceValidity = nonceValidity;
             this.key = key;
-            this.cnonces = cnonces;
+            this.nonces = nonces;
             this.validateUri = validateUri;
         }
 
-        public boolean validate(Request request, String authorization,
-                LoginConfig config) {
+
+        public String getUsername() {
+            return userName;
+        }
+
+
+        public boolean parse(Request request, String authorization) {
             // Validate the authorization credentials format
             if (authorization == null) {
                 return false;
             }
-            if (!authorization.startsWith("Digest ")) {
+
+            Map<String,String> directives;
+            try {
+                directives = HttpParser.parseAuthorizationDigest(
+                        new StringReader(authorization));
+            } catch (IOException e) {
                 return false;
             }
-            authorization = authorization.substring(7).trim();
 
-            // Bugzilla 37132: http://issues.apache.org/bugzilla/show_bug.cgi?id=37132
-            String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)");
+            if (directives == null) {
+                return false;
+            }
 
             method = request.getMethod();
-            String opaque = null;
-
-            for (int i = 0; i < tokens.length; i++) {
-                String currentToken = tokens[i];
-                if (currentToken.length() == 0)
-                    continue;
+            userName = directives.get("username");
+            realmName = directives.get("realm");
+            nonce = directives.get("nonce");
+            nc = directives.get("nc");
+            cnonce = directives.get("cnonce");
+            qop = directives.get("qop");
+            uri = directives.get("uri");
+            response = directives.get("response");
+            opaqueReceived = directives.get("opaque");
 
-                int equalSign = currentToken.indexOf('=');
-                if (equalSign < 0) {
-                    return false;
-                }
-                String currentTokenName =
-                    currentToken.substring(0, equalSign).trim();
-                String currentTokenValue =
-                    currentToken.substring(equalSign + 1).trim();
-                if ("username".equals(currentTokenName))
-                    userName = removeQuotes(currentTokenValue);
-                if ("realm".equals(currentTokenName))
-                    realmName = removeQuotes(currentTokenValue, true);
-                if ("nonce".equals(currentTokenName))
-                    nonce = removeQuotes(currentTokenValue);
-                if ("nc".equals(currentTokenName))
-                    nc = removeQuotes(currentTokenValue);
-                if ("cnonce".equals(currentTokenName))
-                    cnonce = removeQuotes(currentTokenValue);
-                if ("qop".equals(currentTokenName))
-                    qop = removeQuotes(currentTokenValue);
-                if ("uri".equals(currentTokenName))
-                    uri = removeQuotes(currentTokenValue);
-                if ("response".equals(currentTokenName))
-                    response = removeQuotes(currentTokenValue);
-                if ("opaque".equals(currentTokenName))
-                    opaque = removeQuotes(currentTokenValue);
-            }
+            return true;
+        }
 
+        public boolean validate(Request request, LoginConfig config) {
             if ( (userName == null) || (realmName == null) || (nonce == null)
                  || (uri == null) || (response == null) ) {
                 return false;
@@ -608,9 +627,9 @@ public class DigestAuthenticator extends AuthenticatorBase {
             if (!lcRealm.equals(realmName)) {
                 return false;
             }
-            
+
             // Validate the opaque string
-            if (!this.opaque.equals(opaque)) {
+            if (!opaque.equals(opaqueReceived)) {
                 return false;
             }
 
@@ -629,16 +648,15 @@ public class DigestAuthenticator extends AuthenticatorBase {
             long currentTime = System.currentTimeMillis();
             if ((currentTime - nonceTime) > nonceValidity) {
                 nonceStale = true;
-                return false;
+                synchronized (nonces) {
+                    nonces.remove(nonce);
+                }
             }
             String serverIpTimeKey =
                 request.getRemoteAddr() + ":" + nonceTime + ":" + key;
-            byte[] buffer = null;
-            synchronized (md5Helper) {
-                buffer = md5Helper.digest(
-                        serverIpTimeKey.getBytes(Charset.defaultCharset()));
-            }
-            String md5ServerIpTimeKey = md5Encoder.encode(buffer);
+            byte[] buffer = ConcurrentMessageDigest.digestMD5(
+                    serverIpTimeKey.getBytes(B2CConverter.ISO_8859_1));
+            String md5ServerIpTimeKey = MD5Encoder.encode(buffer);
             if (!md5ServerIpTimeKey.equals(md5clientIpTimeKey)) {
                 return false;
             }
@@ -649,7 +667,7 @@ public class DigestAuthenticator extends AuthenticatorBase {
             }
 
             // Validate cnonce and nc
-            // Check if presence of nc and nonce is consistent with presence of qop
+            // Check if presence of nc and Cnonce is consistent with presence of qop
             if (qop == null) {
                 if (cnonce != null || nc != null) {
                     return false;
@@ -670,21 +688,18 @@ public class DigestAuthenticator extends AuthenticatorBase {
                     return false;
                 }
                 NonceInfo info;
-                synchronized (cnonces) {
-                    info = cnonces.get(cnonce);
+                synchronized (nonces) {
+                    info = nonces.get(nonce);
                 }
                 if (info == null) {
-                    info = new NonceInfo();
+                    // Nonce is valid but not in cache. It must have dropped out
+                    // of the cache - force a re-authentication
+                    nonceStale = true;
                 } else {
-                    if (count <= info.getCount()) {
+                    if (!info.nonceCountValid(count)) {
                         return false;
                     }
                 }
-                info.setCount(count);
-                info.setTimestamp(currentTime);
-                synchronized (cnonces) {
-                    cnonces.put(cnonce, info);
-                }
             }
             return true;
         }
@@ -698,11 +713,9 @@ public class DigestAuthenticator extends AuthenticatorBase {
             // MD5(Method + ":" + uri)
             String a2 = method + ":" + uri;
 
-            byte[] buffer;
-            synchronized (md5Helper) {
-                buffer = md5Helper.digest(a2.getBytes(Charset.defaultCharset()));
-            }
-            String md5a2 = md5Encoder.encode(buffer);
+            byte[] buffer = ConcurrentMessageDigest.digestMD5(
+                    a2.getBytes(B2CConverter.ISO_8859_1));
+            String md5a2 = MD5Encoder.encode(buffer);
 
             return realm.authenticate(userName, response, nonce, nc, cnonce,
                     qop, realmName, md5a2);
@@ -711,21 +724,33 @@ public class DigestAuthenticator extends AuthenticatorBase {
     }
 
     private static class NonceInfo {
-        private volatile long count;
         private volatile long timestamp;
-        
-        public void setCount(long l) {
-            count = l;
+        private volatile boolean seen[];
+        private volatile int offset;
+        private volatile int count = 0;
+
+        public NonceInfo(long currentTime, int seenWindowSize) {
+            this.timestamp = currentTime;
+            seen = new boolean[seenWindowSize];
+            offset = seenWindowSize / 2;
         }
-        
-        public long getCount() {
-            return count;
-        }
-        
-        public void setTimestamp(long l) {
-            timestamp = l;
+
+        public synchronized boolean nonceCountValid(long nonceCount) {
+            if ((count - offset) >= nonceCount ||
+                    (nonceCount > count - offset + seen.length)) {
+                return false;
+            }
+            int checkIndex = (int) ((nonceCount + offset) % seen.length);
+            if (seen[checkIndex]) {
+                return false;
+            } else {
+                seen[checkIndex] = true;
+                seen[count % seen.length] = false;
+                count++;
+                return true;
+            }
         }
-        
+
         public long getTimestamp() {
             return timestamp;
         }
diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
index 443b4e1..b4497d7 100644
--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
@@ -31,6 +31,7 @@ import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.catalina.Manager;
 import org.apache.catalina.Realm;
 import org.apache.catalina.Session;
 import org.apache.catalina.connector.Request;
@@ -51,7 +52,7 @@ import org.apache.tomcat.util.http.MimeHeaders;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: FormAuthenticator.java 1189224 2011-10-26 14:02:40Z kkolinko $
+ * @version $Id: FormAuthenticator.java 1408044 2012-11-11 16:42:02Z kkolinko $
  */
 
 public class FormAuthenticator
@@ -320,6 +321,7 @@ public class FormAuthenticator
                 SavedRequest saved = new SavedRequest();
                 saved.setMethod("GET");
                 saved.setRequestURI(uri);
+                saved.setDecodedRequestURI(uri);
                 request.getSessionInternal(true).setNote(
                         Constants.FORM_REQUEST_NOTE, saved);
                 response.sendRedirect(response.encodeRedirectURL(uri));
@@ -351,6 +353,7 @@ public class FormAuthenticator
                 SavedRequest saved = new SavedRequest();
                 saved.setMethod("GET");
                 saved.setRequestURI(uri);
+                saved.setDecodedRequestURI(uri);
                 session.setNote(Constants.FORM_REQUEST_NOTE, saved);
                 response.sendRedirect(response.encodeRedirectURL(uri));
             }
@@ -402,6 +405,15 @@ public class FormAuthenticator
             return;
         }
 
+        if (getChangeSessionIdOnAuthentication()) {
+            Session session = request.getSessionInternal(false);
+            if (session != null) {
+                Manager manager = request.getContext().getManager();
+                manager.changeSessionId(session);
+                request.changeSessionId(session.getId());
+            }
+        }
+
         // Always use GET for the login page, regardless of the method used
         String oldMethod = request.getMethod();
         request.getCoyoteRequest().method().setString("GET");
@@ -498,12 +510,11 @@ public class FormAuthenticator
     }
 
       // Does the request URI match?
-      String requestURI = request.getRequestURI();
-      if (requestURI == null) {
+      String decodedRequestURI = request.getDecodedRequestURI();
+      if (decodedRequestURI == null) {
         return (false);
     }
-      return (requestURI.equals(sreq.getRequestURI()));
-
+      return (decodedRequestURI.equals(sreq.getDecodedRequestURI()));
     }
 
 
@@ -659,10 +670,10 @@ public class FormAuthenticator
         saved.setMethod(request.getMethod());
         saved.setQueryString(request.getQueryString());
         saved.setRequestURI(request.getRequestURI());
+        saved.setDecodedRequestURI(request.getDecodedRequestURI());
 
         // Stash the SavedRequest in our session for later use
         session.setNote(Constants.FORM_REQUEST_NOTE, saved);
-
     }
 
 
diff --git a/java/org/apache/catalina/authenticator/SavedRequest.java b/java/org/apache/catalina/authenticator/SavedRequest.java
index ae15d04..30fe03a 100644
--- a/java/org/apache/catalina/authenticator/SavedRequest.java
+++ b/java/org/apache/catalina/authenticator/SavedRequest.java
@@ -39,7 +39,7 @@ import org.apache.tomcat.util.buf.ByteChunk;
  * internal collection classes is performed.
  *
  * @author Craig R. McClanahan
- * @version $Id: SavedRequest.java 1043272 2010-12-08 01:31:51Z markt $
+ * @version $Id: SavedRequest.java 1372394 2012-08-13 12:29:51Z markt $
  */
 
 public final class SavedRequest {
@@ -147,6 +147,21 @@ public final class SavedRequest {
 
     
     /**
+     * The decode request URI associated with this Request. Path parameters are
+     * also excluded
+     */
+    private String decodedRequestURI = null;
+
+    public String getDecodedRequestURI() {
+        return (this.decodedRequestURI);
+    }
+
+    public void setDecodedRequestURI(String decodedRequestURI) {
+        this.decodedRequestURI = decodedRequestURI;
+    }
+
+
+    /**
      * The body of this request.
      */
     private ByteChunk body = null;
diff --git a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
index 3c36c6a..e6aba7b 100644
--- a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.security.Principal;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.regex.Pattern;
 
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginContext;
@@ -71,6 +72,24 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
         this.storeDelegatedCredential = storeDelegatedCredential;
     }
 
+    private Pattern noKeepAliveUserAgents = null;
+    public String getNoKeepAliveUserAgents() {
+        Pattern p = noKeepAliveUserAgents;
+        if (p == null) {
+            return null;
+        } else {
+            return p.pattern();
+        }
+    }
+    public void setNoKeepAliveUserAgents(String noKeepAliveUserAgents) {
+        if (noKeepAliveUserAgents == null ||
+                noKeepAliveUserAgents.length() == 0) {
+            this.noKeepAliveUserAgents = null;
+        } else {
+            this.noKeepAliveUserAgents = Pattern.compile(noKeepAliveUserAgents);
+        }
+    }
+
 
     @Override
     protected String getAuthMethod() {
@@ -269,6 +288,16 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
         if (principal != null) {
             register(request, response, principal, Constants.SPNEGO_METHOD,
                     principal.getName(), null);
+
+            Pattern p = noKeepAliveUserAgents;
+            if (p != null) {
+                MessageBytes ua =
+                        request.getCoyoteRequest().getMimeHeaders().getValue(
+                                "user-agent");
+                if (ua != null && p.matcher(ua.toString()).matches()) {
+                    response.setHeader("Connection", "close");
+                }
+            }
             return true;
         }
 
diff --git a/java/org/apache/catalina/connector/Connector.java b/java/org/apache/catalina/connector/Connector.java
index 6ff50d8..b3f2830 100644
--- a/java/org/apache/catalina/connector/Connector.java
+++ b/java/org/apache/catalina/connector/Connector.java
@@ -43,7 +43,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: Connector.java 1350306 2012-06-14 15:59:15Z kkolinko $
+ * @version $Id: Connector.java 1353509 2012-06-25 13:05:03Z markt $
  */
 
 
@@ -970,6 +970,13 @@ public class Connector extends LifecycleMBeanBase  {
             setParseBodyMethods(getParseBodyMethods());
         }
 
+        if (protocolHandler.isAprRequired() &&
+                !AprLifecycleListener.isAprAvailable()) {
+            throw new LifecycleException(
+                    sm.getString("coyoteConnector.protocolHandlerNoApr",
+                            getProtocolHandlerClassName()));
+        }
+
         try {
             protocolHandler.init();
         } catch (Exception e) {
diff --git a/java/org/apache/catalina/connector/CoyoteAdapter.java b/java/org/apache/catalina/connector/CoyoteAdapter.java
index bccfdfb..1c7bf2b 100644
--- a/java/org/apache/catalina/connector/CoyoteAdapter.java
+++ b/java/org/apache/catalina/connector/CoyoteAdapter.java
@@ -55,7 +55,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: CoyoteAdapter.java 1335700 2012-05-08 19:07:09Z markt $
+ * @version $Id: CoyoteAdapter.java 1409036 2012-11-13 23:55:26Z markt $
  */
 public class CoyoteAdapter implements Adapter {
 
@@ -290,7 +290,7 @@ public class CoyoteAdapter implements Adapter {
             if (status==SocketStatus.TIMEOUT) {
                 success = true;
                 if (!asyncConImpl.timeout()) {
-                    asyncConImpl.setErrorState(null);
+                    asyncConImpl.setErrorState(null, false);
                 }
             }
             if (request.isAsyncDispatching()) {
@@ -299,7 +299,7 @@ public class CoyoteAdapter implements Adapter {
                 Throwable t = (Throwable) request.getAttribute(
                         RequestDispatcher.ERROR_EXCEPTION);
                 if (t != null) {
-                    asyncConImpl.setErrorState(t);
+                    asyncConImpl.setErrorState(t, true);
                 }
             }
 
diff --git a/java/org/apache/catalina/connector/LocalStrings.properties b/java/org/apache/catalina/connector/LocalStrings.properties
index 83d2f00..880cbcd 100644
--- a/java/org/apache/catalina/connector/LocalStrings.properties
+++ b/java/org/apache/catalina/connector/LocalStrings.properties
@@ -22,6 +22,7 @@ coyoteConnector.invalidPort=The connector cannot start since the specified port
 coyoteConnector.protocolHandlerDestroyFailed=Protocol handler destroy failed
 coyoteConnector.protocolHandlerInitializationFailed=Protocol handler initialization failed
 coyoteConnector.protocolHandlerInstantiationFailed=Protocol handler instantiation failed
+coyoteConnector.protocolHandlerNoApr=The configured protocol [{0}] requires the APR/native library which is not available
 coyoteConnector.protocolHandlerStartFailed=Protocol handler start failed
 coyoteConnector.protocolRegistrationFailed=Protocol JMX registration failed
 coyoteConnector.protocolHandlerPauseFailed=Protocol handler pause failed
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index 1e2c357..151b72f 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 1335733 2012-05-08 20:07:23Z markt $
+ * @version $Id: Request.java 1356509 2012-07-02 22:43:32Z kkolinko $
  */
 
 public class Request
@@ -470,7 +470,16 @@ public class Request
         subject = null;
         sessionParsed = false;
         parametersParsed = false;
-        parts = null;
+        if (parts != null) {
+            for (Part part: parts) {
+                try {
+                    part.delete();
+                } catch (IOException ignored) {
+                    // ApplicationPart.delete() never throws an IOEx
+                }
+            }
+            parts = null;
+        }
         partsParseException = null;
         cookiesParsed = false;
         locales.clear();
diff --git a/java/org/apache/catalina/connector/Response.java b/java/org/apache/catalina/connector/Response.java
index b4b5b95..5c144a6 100644
--- a/java/org/apache/catalina/connector/Response.java
+++ b/java/org/apache/catalina/connector/Response.java
@@ -20,7 +20,6 @@ package org.apache.catalina.connector;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.io.StringReader;
 import java.net.MalformedURLException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -28,6 +27,7 @@ import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.List;
@@ -53,9 +53,7 @@ import org.apache.tomcat.util.buf.UEncoder;
 import org.apache.tomcat.util.http.FastHttpDateFormat;
 import org.apache.tomcat.util.http.MimeHeaders;
 import org.apache.tomcat.util.http.ServerCookie;
-import org.apache.tomcat.util.http.parser.AstMediaType;
-import org.apache.tomcat.util.http.parser.HttpParser;
-import org.apache.tomcat.util.http.parser.ParseException;
+import org.apache.tomcat.util.http.parser.MediaTypeCache;
 import org.apache.tomcat.util.net.URL;
 import org.apache.tomcat.util.res.StringManager;
 
@@ -64,7 +62,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Craig R. McClanahan
- * @version $Id: Response.java 1350247 2012-06-14 14:04:20Z markt $
+ * @version $Id: Response.java 1405416 2012-11-03 20:55:42Z markt $
  */
 
 public class Response
@@ -73,6 +71,9 @@ public class Response
 
     // ----------------------------------------------------------- Constructors
 
+    private static final MediaTypeCache MEDIA_TYPE_CACHE =
+            new MediaTypeCache(100);
+
     /**
      * Compliance with SRV.15.2.22.1. A call to Response.getWriter() if no
      * character encoding has been specified will result in subsequent calls to
@@ -125,7 +126,9 @@ public class Response
 
     /**
      * Associated Catalina connector.
+     * @deprecated  Unused
      */
+    @Deprecated
     protected Connector connector;
 
     /**
@@ -800,24 +803,20 @@ public class Response
             return;
         }
 
-        AstMediaType m = null;
-        HttpParser hp = new HttpParser(new StringReader(type));
-        try {
-             m = hp.MediaType();
-        } catch (ParseException e) {
+        String[] m = MEDIA_TYPE_CACHE.parse(type);
+        if (m == null) {
             // Invalid - Assume no charset and just pass through whatever
             // the user provided.
             coyoteResponse.setContentTypeNoCharset(type);
             return;
         }
 
-        coyoteResponse.setContentTypeNoCharset(m.toStringNoCharset());
+        coyoteResponse.setContentTypeNoCharset(m[0]);
 
-        String charset = m.getCharset();
-        if (charset != null) {
+        if (m[1] != null) {
             // Ignore charset if getWriter() has already been called
             if (!usingWriter) {
-                coyoteResponse.setCharacterEncoding(charset);
+                coyoteResponse.setCharacterEncoding(m[1]);
                 isCharacterEncodingSet = true;
             }
         }
@@ -894,23 +893,12 @@ public class Response
     // --------------------------------------------------- HttpResponse Methods
 
 
-    /**
-     * Return the value for the specified header, or <code>null</code> if this
-     * header has not been set.  If more than one value was added for this
-     * name, only the first is returned; use {@link #getHeaders(String)} to
-     * retrieve all of them.
-     *
-     * @param name Header name to look up
-     */
     @Override
     public String getHeader(String name) {
         return coyoteResponse.getMimeHeaders().getHeader(name);
     }
 
 
-    /**
-     * Return an Iterable of all the header names set for this response.
-     */
     @Override
     public Collection<String> getHeaderNames() {
 
@@ -925,12 +913,6 @@ public class Response
     }
 
 
-    /**
-     * Return a Collection of all the header values associated with the
-     * specified header name.
-     *
-     * @param name Header name to look up
-     */
     @Override
     public Collection<String> getHeaders(String name) {
 
@@ -953,9 +935,6 @@ public class Response
     }
 
 
-    /**
-     * Return the HTTP status code associated with this Response.
-     */
     @Override
     public int getStatus() {
         return coyoteResponse.getStatus();
@@ -1239,7 +1218,14 @@ public class Response
     @Override
     public String encodeURL(String url) {
 
-        String absolute = toAbsolute(url);
+        String absolute;
+        try {
+            absolute = toAbsolute(url);
+        } catch (IllegalArgumentException iae) {
+            // Relative URL
+            return url;
+        }
+
         if (isEncodeable(absolute)) {
             // W3c spec clearly said
             if (url.equalsIgnoreCase("")) {
@@ -1752,6 +1738,19 @@ public class Response
      * Code borrowed heavily from CoyoteAdapter.normalize()
      */
     private void normalize(CharChunk cc) {
+        // Strip query string and/or fragment first as doing it this way makes
+        // the normalization logic a lot simpler
+        int truncate = cc.indexOf('?');
+        if (truncate == -1) {
+            truncate = cc.indexOf('#');
+        }
+        char[] truncateCC = null;
+        if (truncate > -1) {
+            truncateCC = Arrays.copyOfRange(cc.getBuffer(),
+                    cc.getStart() + truncate, cc.getEnd());
+            cc.setEnd(cc.getStart() + truncate);
+        }
+
         if (cc.endsWith("/.") || cc.endsWith("/..")) {
             try {
                 cc.append('/');
@@ -1794,7 +1793,7 @@ public class Response
             if (index < 0) {
                 break;
             }
-            // Prevent from going outside our context
+            // Can't go above the server root
             if (index == startIndex) {
                 throw new IllegalArgumentException();
             }
@@ -1810,6 +1809,15 @@ public class Response
             cc.setEnd(end);
             index = index2;
         }
+
+        // Add the query string and/or fragment (if present) back in
+        if (truncateCC != null) {
+            try {
+                cc.append(truncateCC, 0, truncateCC.length);
+            } catch (IOException ioe) {
+                throw new IllegalArgumentException(ioe);
+            }
+        }
     }
 
     private void copyChars(char[] c, int dest, int src, int len) {
diff --git a/java/org/apache/catalina/core/ApplicationContext.java b/java/org/apache/catalina/core/ApplicationContext.java
index 47d604b..b230608 100644
--- a/java/org/apache/catalina/core/ApplicationContext.java
+++ b/java/org/apache/catalina/core/ApplicationContext.java
@@ -84,7 +84,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: ApplicationContext.java 1345359 2012-06-01 21:42:24Z kkolinko $
+ * @version $Id: ApplicationContext.java 1357410 2012-07-04 21:10:48Z markt $
  */
 
 public class ApplicationContext
@@ -169,7 +169,7 @@ public class ApplicationContext
     /**
      * The merged context initialization parameters for this Context.
      */
-    private Map<String,String> parameters =
+    private final ConcurrentHashMap<String,String> parameters =
         new ConcurrentHashMap<String,String>();
 
 
@@ -534,7 +534,8 @@ public class ApplicationContext
             String hostName = context.getParent().getName();
             try {
                 resources.lookup(normPath);
-                URI uri = new URI("jndi", getJNDIUri(hostName, fullPath), null);
+                URI uri = new URI("jndi", null, "", -1,
+                        getJNDIUri(hostName, fullPath), null, null);
                 return new URL(null, uri.toString(),
                         new DirContextURLStreamHandler(resources));
             } catch (NamingException e) {
@@ -752,17 +753,14 @@ public class ApplicationContext
     public void removeAttribute(String name) {
 
         Object value = null;
-        boolean found = false;
 
         // Remove the specified attribute
         // Check for read only attribute
-        if (readOnlyAttributes.containsKey(name))
+        if (readOnlyAttributes.containsKey(name)){
             return;
-        found = attributes.containsKey(name);
-        if (found) {
-            value = attributes.get(name);
-            attributes.remove(name);
-        } else {
+        }
+        value = attributes.remove(name);
+        if (value == null) {
             return;
         }
 
@@ -1259,12 +1257,7 @@ public class ApplicationContext
 
     @Override
     public boolean setInitParameter(String name, String value) {
-        if (parameters.containsKey(name)) {
-            return false;
-        }
-        
-        parameters.put(name, value);
-        return true;
+        return parameters.putIfAbsent(name, value) == null;
     }
     
     
diff --git a/java/org/apache/catalina/core/ApplicationDispatcher.java b/java/org/apache/catalina/core/ApplicationDispatcher.java
index 6948f08..17d9dfc 100644
--- a/java/org/apache/catalina/core/ApplicationDispatcher.java
+++ b/java/org/apache/catalina/core/ApplicationDispatcher.java
@@ -14,8 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-
 package org.apache.catalina.core;
 
 import java.io.IOException;
@@ -37,6 +35,7 @@ import javax.servlet.UnavailableException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.catalina.AsyncDispatcher;
 import org.apache.catalina.Context;
 import org.apache.catalina.Globals;
 import org.apache.catalina.InstanceEvent;
@@ -61,11 +60,9 @@ import org.apache.tomcat.util.res.StringManager;
  * <code>javax.servlet.ServletResponseWrapper</code>.
  *
  * @author Craig R. McClanahan
- * @version $Id: ApplicationDispatcher.java 1345689 2012-06-03 15:54:28Z markt $
+ * @version $Id: ApplicationDispatcher.java 1373154 2012-08-14 22:37:56Z markt $
  */
-
-final class ApplicationDispatcher
-    implements RequestDispatcher {
+final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher {
 
     protected static final boolean STRICT_SERVLET_COMPLIANCE;
 
@@ -91,8 +88,7 @@ final class ApplicationDispatcher
         private ServletRequest request;
         private ServletResponse response;
 
-        PrivilegedForward(ServletRequest request, ServletResponse response)
-        {
+        PrivilegedForward(ServletRequest request, ServletResponse response) {
             this.request = request;
             this.response = response;
         }
@@ -109,22 +105,36 @@ final class ApplicationDispatcher
         private ServletRequest request;
         private ServletResponse response;
 
-        PrivilegedInclude(ServletRequest request, ServletResponse response)
-        {
+        PrivilegedInclude(ServletRequest request, ServletResponse response) {
             this.request = request;
             this.response = response;
         }
 
         @Override
         public Void run() throws ServletException, IOException {
-            DispatcherType type = DispatcherType.INCLUDE;
-            if (request.getDispatcherType()==DispatcherType.ASYNC) type = DispatcherType.ASYNC; 
-            doInclude(request,response,type);
+            doInclude(request, response);
             return null;
         }
     }
 
-    
+    protected class PrivilegedDispatch implements
+            PrivilegedExceptionAction<Void> {
+        private final ServletRequest request;
+        private final ServletResponse response;
+
+        PrivilegedDispatch(ServletRequest request, ServletResponse response) {
+            this.request = request;
+            this.response = response;
+        }
+
+        @Override
+        public Void run() throws ServletException, IOException {
+            doDispatch(request, response);
+            return null;
+        }
+    }
+
+
     /**
      * Used to pass state when the request dispatcher is used. Using instance
      * variables causes threading issues and state is too complex to pass and
@@ -457,7 +467,7 @@ final class ApplicationDispatcher
                                 State state)
         throws IOException, ServletException {
                 
-        DispatcherType disInt = (DispatcherType) request.getAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR);
+        DispatcherType disInt = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
         if (disInt != null) {
             boolean doInvoke = true;
             
@@ -468,12 +478,12 @@ final class ApplicationDispatcher
 
             if (doInvoke) {
                 if (disInt != DispatcherType.ERROR) {
-                    state.outerRequest.setAttribute
-                        (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
-                         getCombinedPath());
-                    state.outerRequest.setAttribute
-                        (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-                         DispatcherType.FORWARD);
+                    state.outerRequest.setAttribute(
+                            Globals.DISPATCHER_REQUEST_PATH_ATTR,
+                            getCombinedPath());
+                    state.outerRequest.setAttribute(
+                            Globals.DISPATCHER_TYPE_ATTR,
+                            DispatcherType.FORWARD);
                     invoke(state.outerRequest, response, state);
                 } else {
                     invoke(state.outerRequest, response, state);
@@ -531,15 +541,13 @@ final class ApplicationDispatcher
                 throw (IOException) e;
             }
         } else {
-            DispatcherType type = DispatcherType.INCLUDE;
-            if (request.getDispatcherType()==DispatcherType.ASYNC) type = DispatcherType.ASYNC; 
-            doInclude(request,response,type);
+            doInclude(request, response);
         }
     }
 
-    private void doInclude(ServletRequest request, ServletResponse response, DispatcherType type)
-        throws ServletException, IOException
-    {
+    private void doInclude(ServletRequest request, ServletResponse response)
+            throws ServletException, IOException {
+
         // Set up to handle the specified request and response
         State state = new State(request, response, true);
 
@@ -559,10 +567,9 @@ final class ApplicationDispatcher
             wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name);
             if (servletPath != null)
                 wrequest.setServletPath(servletPath);
-            wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-                    type);
-            wrequest.setAttribute(
-                    ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+            wrequest.setAttribute(Globals.DISPATCHER_TYPE_ATTR,
+                    DispatcherType.INCLUDE);
+            wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
                     getCombinedPath());
             invoke(state.outerRequest, state.outerResponse, state);
         }
@@ -591,10 +598,9 @@ final class ApplicationDispatcher
                 wrequest.setQueryParams(queryString);
             }
             
-            wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-                    type);
-            wrequest.setAttribute(
-                    ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+            wrequest.setAttribute(Globals.DISPATCHER_TYPE_ATTR,
+                    DispatcherType.INCLUDE);
+            wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
                     getCombinedPath());
             invoke(state.outerRequest, state.outerResponse, state);
         }
@@ -602,6 +608,59 @@ final class ApplicationDispatcher
     }
 
 
+    @Override
+    public void dispatch(ServletRequest request, ServletResponse response)
+            throws ServletException, IOException {
+        if (Globals.IS_SECURITY_ENABLED) {
+            try {
+                PrivilegedDispatch dp = new PrivilegedDispatch(request,response);
+                AccessController.doPrivileged(dp);
+            } catch (PrivilegedActionException pe) {
+                Exception e = pe.getException();
+
+                if (e instanceof ServletException)
+                    throw (ServletException) e;
+                throw (IOException) e;
+            }
+        } else {
+            doDispatch(request, response);
+        }
+    }
+
+    private void doDispatch(ServletRequest request, ServletResponse response)
+            throws ServletException, IOException {
+
+        // Set up to handle the specified request and response
+        State state = new State(request, response, false);
+
+        // Create a wrapped response to use for this request
+        wrapResponse(state);
+
+        ApplicationHttpRequest wrequest =
+            (ApplicationHttpRequest) wrapRequest(state);
+
+        if (queryString != null) {
+            wrequest.setQueryParams(queryString);
+        }
+
+        wrequest.setAttribute(Globals.DISPATCHER_TYPE_ATTR,
+                DispatcherType.ASYNC);
+        wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
+                getCombinedPath());
+
+        wrequest.setContextPath(context.getPath());
+        wrequest.setRequestURI(requestURI);
+        wrequest.setServletPath(servletPath);
+        wrequest.setPathInfo(pathInfo);
+        if (queryString != null) {
+            wrequest.setQueryString(queryString);
+            wrequest.setQueryParams(queryString);
+        }
+
+        invoke(state.outerRequest, state.outerResponse, state);
+    }
+
+
     // -------------------------------------------------------- Private Methods
 
 
@@ -785,6 +844,12 @@ final class ApplicationDispatcher
         if (state.wrapRequest == null)
             return;
 
+        if (state.outerRequest.isAsyncStarted()) {
+            if (!state.outerRequest.getAsyncContext().hasOriginalRequestAndResponse()) {
+                return;
+            }
+        }
+
         ServletRequest previous = null;
         ServletRequest current = state.outerRequest;
         while (current != null) {
@@ -821,6 +886,12 @@ final class ApplicationDispatcher
         if (state.wrapResponse == null)
             return;
 
+        if (state.outerRequest.isAsyncStarted()) {
+            if (!state.outerRequest.getAsyncContext().hasOriginalRequestAndResponse()) {
+                return;
+            }
+        }
+
         ServletResponse previous = null;
         ServletResponse current = state.outerResponse;
         while (current != null) {
diff --git a/java/org/apache/catalina/core/ApplicationFilterFactory.java b/java/org/apache/catalina/core/ApplicationFilterFactory.java
index 7a8da63..3daa178 100644
--- a/java/org/apache/catalina/core/ApplicationFilterFactory.java
+++ b/java/org/apache/catalina/core/ApplicationFilterFactory.java
@@ -45,10 +45,18 @@ public final class ApplicationFilterFactory {
     // -------------------------------------------------------------- Constants
 
 
-    public static final String DISPATCHER_TYPE_ATTR = 
-        Globals.DISPATCHER_TYPE_ATTR;
+    /**
+     * @deprecated  Use {@link Globals#DISPATCHER_TYPE_ATTR}
+     */
+    @Deprecated
+    public static final String DISPATCHER_TYPE_ATTR =
+            Globals.DISPATCHER_TYPE_ATTR;
+    /**
+     * @deprecated  Use {@link Globals#DISPATCHER_REQUEST_PATH_ATTR}
+     */
+    @Deprecated
     public static final String DISPATCHER_REQUEST_PATH_ATTR = 
-        Globals.DISPATCHER_REQUEST_PATH_ATTR;
+            Globals.DISPATCHER_REQUEST_PATH_ATTR;
 
     private static ApplicationFilterFactory factory = null;
 
@@ -87,11 +95,13 @@ public final class ApplicationFilterFactory {
 
         // get the dispatcher type
         DispatcherType dispatcher = null; 
-        if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
-            dispatcher = (DispatcherType) request.getAttribute(DISPATCHER_TYPE_ATTR);
+        if (request.getAttribute(Globals.DISPATCHER_TYPE_ATTR) != null) {
+            dispatcher = (DispatcherType) request.getAttribute(
+                    Globals.DISPATCHER_TYPE_ATTR);
         }
         String requestPath = null;
-        Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
+        Object attribute = request.getAttribute(
+                Globals.DISPATCHER_REQUEST_PATH_ATTR);
         
         if (attribute != null){
             requestPath = attribute.toString();
diff --git a/java/org/apache/catalina/core/ApplicationFilterRegistration.java b/java/org/apache/catalina/core/ApplicationFilterRegistration.java
index 93a6227..2670c8f 100644
--- a/java/org/apache/catalina/core/ApplicationFilterRegistration.java
+++ b/java/org/apache/catalina/core/ApplicationFilterRegistration.java
@@ -72,9 +72,9 @@ public class ApplicationFilterRegistration
             }
         
             if (isMatchAfter) {
-                context.addFilterMapBefore(filterMap);
-            } else {
                 context.addFilterMap(filterMap);
+            } else {
+                context.addFilterMapBefore(filterMap);
             }
         }
         // else error?
@@ -101,9 +101,9 @@ public class ApplicationFilterRegistration
             }
         
             if (isMatchAfter) {
-                context.addFilterMapBefore(filterMap);
-            } else {
                 context.addFilterMap(filterMap);
+            } else {
+                context.addFilterMapBefore(filterMap);
             }
         }
         // else error?
diff --git a/java/org/apache/catalina/core/ApplicationJspPropertyGroupDescriptor.java b/java/org/apache/catalina/core/ApplicationJspPropertyGroupDescriptor.java
index f3671eb..612a510 100644
--- a/java/org/apache/catalina/core/ApplicationJspPropertyGroupDescriptor.java
+++ b/java/org/apache/catalina/core/ApplicationJspPropertyGroupDescriptor.java
@@ -14,11 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.catalina.core;
 
 import java.util.Collection;
-import java.util.HashSet;
 
 import javax.servlet.descriptor.JspPropertyGroupDescriptor;
 
@@ -28,6 +26,10 @@ import org.apache.catalina.deploy.JspPropertyGroup;
 public class ApplicationJspPropertyGroupDescriptor
         implements JspPropertyGroupDescriptor{
 
+    /**
+     * @deprecated  Will be made private in 8.0.x
+     */
+    @Deprecated
     JspPropertyGroup jspPropertyGroup;
 
     
@@ -160,13 +162,6 @@ public class ApplicationJspPropertyGroupDescriptor
     
     @Override
     public Collection<String> getUrlPatterns() {
-        Collection<String> result = new HashSet<String>();
-        
-        if (jspPropertyGroup.getUrlPattern() != null) {
-            result.add(jspPropertyGroup.getUrlPattern());
-        }
-        
-        return result;
+        return jspPropertyGroup.getUrlPatterns();
     }
-
 }
diff --git a/java/org/apache/catalina/core/AprLifecycleListener.java b/java/org/apache/catalina/core/AprLifecycleListener.java
index 06161e9..91acf09 100644
--- a/java/org/apache/catalina/core/AprLifecycleListener.java
+++ b/java/org/apache/catalina/core/AprLifecycleListener.java
@@ -39,7 +39,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Filip Hanik
- * @version $Id: AprLifecycleListener.java 1349932 2012-06-13 15:59:02Z markt $
+ * @version $Id: AprLifecycleListener.java 1353504 2012-06-25 13:01:53Z markt $
  * @since 4.1
  */
 
@@ -71,6 +71,7 @@ public class AprLifecycleListener
     protected static String SSLRandomSeed = "builtin";
     protected static boolean sslInitialized = false;
     protected static boolean aprInitialized = false;
+    @Deprecated
     protected static boolean sslAvailable = false;
     protected static boolean aprAvailable = false;
     protected static boolean fipsModeActive = false;
@@ -161,7 +162,7 @@ public class AprLifecycleListener
         int patch = 0;
         int apver = 0;
         int rqver = TCN_REQUIRED_MAJOR * 1000 + TCN_REQUIRED_MINOR * 100 + TCN_REQUIRED_PATCH;
-        int rcver = TCN_REQUIRED_MAJOR * 1000 + TCN_REQUIRED_MINOR * 100 + TCN_RECOMMENDED_PV;
+        int rcver = TCN_REQUIRED_MAJOR * 1000 + TCN_RECOMMENDED_MINOR * 100 + TCN_RECOMMENDED_PV;
 
         if (aprInitialized) {
             return;
diff --git a/java/org/apache/catalina/core/AsyncContextImpl.java b/java/org/apache/catalina/core/AsyncContextImpl.java
index b1fdee0..1b4d445 100644
--- a/java/org/apache/catalina/core/AsyncContextImpl.java
+++ b/java/org/apache/catalina/core/AsyncContextImpl.java
@@ -30,7 +30,6 @@ import javax.naming.NamingException;
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
 import javax.servlet.AsyncListener;
-import javax.servlet.DispatcherType;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
@@ -39,8 +38,11 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.catalina.AsyncDispatcher;
 import org.apache.catalina.Context;
 import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.Valve;
 import org.apache.catalina.connector.Request;
 import org.apache.coyote.ActionCode;
 import org.apache.coyote.AsyncContextCallback;
@@ -95,36 +97,67 @@ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback {
         List<AsyncListenerWrapper> listenersCopy =
             new ArrayList<AsyncListenerWrapper>();
         listenersCopy.addAll(listeners);
-        for (AsyncListenerWrapper listener : listenersCopy) {
-            try {
-                listener.fireOnComplete(event);
-            } catch (IOException ioe) {
-                log.warn("onComplete() failed for listener of type [" +
-                        listener.getClass().getName() + "]", ioe);
+
+        ClassLoader oldCL;
+        if (Globals.IS_SECURITY_ENABLED) {
+            PrivilegedAction<ClassLoader> pa = new PrivilegedGetTccl();
+            oldCL = AccessController.doPrivileged(pa);
+        } else {
+            oldCL = Thread.currentThread().getContextClassLoader();
+        }
+        ClassLoader newCL = context.getLoader().getClassLoader();
+
+        try {
+            if (Globals.IS_SECURITY_ENABLED) {
+                PrivilegedAction<Void> pa = new PrivilegedSetTccl(newCL);
+                AccessController.doPrivileged(pa);
+            } else {
+                Thread.currentThread().setContextClassLoader(newCL);
+            }
+            for (AsyncListenerWrapper listener : listenersCopy) {
+                try {
+                    listener.fireOnComplete(event);
+                } catch (IOException ioe) {
+                    log.warn("onComplete() failed for listener of type [" +
+                            listener.getClass().getName() + "]", ioe);
+                }
+            }
+        } finally {
+            if (Globals.IS_SECURITY_ENABLED) {
+                PrivilegedAction<Void> pa = new PrivilegedSetTccl(oldCL);
+                AccessController.doPrivileged(pa);
+            } else {
+                Thread.currentThread().setContextClassLoader(oldCL);
             }
         }
     }
     
-    public boolean timeout() throws IOException {
+    public boolean timeout() {
         AtomicBoolean result = new AtomicBoolean();
         request.getCoyoteRequest().action(ActionCode.ASYNC_TIMEOUT, result);
         
         if (result.get()) {
-            boolean listenerInvoked = false;
-            List<AsyncListenerWrapper> listenersCopy =
-                new ArrayList<AsyncListenerWrapper>();
-            listenersCopy.addAll(listeners);
-            for (AsyncListenerWrapper listener : listenersCopy) {
-                listener.fireOnTimeout(event);
-                listenerInvoked = true;
-            }
-            if (listenerInvoked) {
+
+            ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
+            ClassLoader newCL = request.getContext().getLoader().getClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(newCL);
+                List<AsyncListenerWrapper> listenersCopy =
+                    new ArrayList<AsyncListenerWrapper>();
+                listenersCopy.addAll(listeners);
+                for (AsyncListenerWrapper listener : listenersCopy) {
+                    try {
+                        listener.fireOnTimeout(event);
+                    } catch (IOException ioe) {
+                        log.warn("onTimeout() failed for listener of type [" +
+                                listener.getClass().getName() + "]", ioe);
+                    }
+                }
                 request.getCoyoteRequest().action(
                         ActionCode.ASYNC_IS_TIMINGOUT, result);
                 return !result.get();
-            } else {
-                // No listeners, container calls complete
-                complete();
+            } finally {
+                Thread.currentThread().setContextClassLoader(oldCL);
             }
         }
         return true;
@@ -153,30 +186,32 @@ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback {
         }
         check();
         if (request.getAttribute(ASYNC_REQUEST_URI)==null) {
-            request.setAttribute(ASYNC_REQUEST_URI, request.getRequestURI()+"?"+request.getQueryString());
+            request.setAttribute(ASYNC_REQUEST_URI, request.getRequestURI());
             request.setAttribute(ASYNC_CONTEXT_PATH, request.getContextPath());
             request.setAttribute(ASYNC_SERVLET_PATH, request.getServletPath());
+            request.setAttribute(ASYNC_PATH_INFO, request.getPathInfo());
             request.setAttribute(ASYNC_QUERY_STRING, request.getQueryString());
         }
         final RequestDispatcher requestDispatcher = context.getRequestDispatcher(path);
-        final HttpServletRequest servletRequest = (HttpServletRequest)getRequest();
-        final HttpServletResponse servletResponse = (HttpServletResponse)getResponse();
+        if (!(requestDispatcher instanceof AsyncDispatcher)) {
+            throw new UnsupportedOperationException(
+                    sm.getString("asyncContextImpl.noAsyncDispatcher"));
+        }
+        final AsyncDispatcher applicationDispatcher =
+                (AsyncDispatcher) requestDispatcher;
+        final HttpServletRequest servletRequest =
+                (HttpServletRequest) getRequest();
+        final HttpServletResponse servletResponse =
+                (HttpServletResponse) getResponse();
         Runnable run = new Runnable() {
             @Override
             public void run() {
                 request.getCoyoteRequest().action(ActionCode.ASYNC_DISPATCHED, null);
-                DispatcherType type = (DispatcherType)request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
                 try {
-                    //piggy back on the request dispatcher to ensure that filters etc get called.
-                    //TODO SERVLET3 - async should this be include/forward or a new dispatch type
-                    //javadoc suggests include with the type of DispatcherType.ASYNC
-                    request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ASYNC);
-                    requestDispatcher.include(servletRequest, servletResponse);
+                    applicationDispatcher.dispatch(servletRequest, servletResponse);
                 }catch (Exception x) {
                     //log.error("Async.dispatch",x);
                     throw new RuntimeException(x);
-                }finally {
-                    request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, type);
                 }
             }
         };
@@ -224,7 +259,6 @@ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback {
         listeners.add(wrapper);
     }
 
-    @SuppressWarnings("unchecked")
     @Override
     public <T extends AsyncListener> T createListener(Class<T> clazz)
             throws ServletException {
@@ -346,20 +380,50 @@ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback {
     }
 
 
-    public void setErrorState(Throwable t) {
+    public void setErrorState(Throwable t, boolean fireOnError) {
         if (t!=null) request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
         request.getCoyoteRequest().action(ActionCode.ASYNC_ERROR, null);
-        AsyncEvent errorEvent = new AsyncEvent(event.getAsyncContext(),
-                event.getSuppliedRequest(), event.getSuppliedResponse(), t);
-        List<AsyncListenerWrapper> listenersCopy =
-            new ArrayList<AsyncListenerWrapper>();
-        listenersCopy.addAll(listeners);
-        for (AsyncListenerWrapper listener : listenersCopy) {
-            try {
-                listener.fireOnError(errorEvent);
-            } catch (IOException ioe) {
-                log.warn("onStartAsync() failed for listener of type [" +
-                        listener.getClass().getName() + "]", ioe);
+
+        if (fireOnError) {
+            AsyncEvent errorEvent = new AsyncEvent(event.getAsyncContext(),
+                    event.getSuppliedRequest(), event.getSuppliedResponse(), t);
+            List<AsyncListenerWrapper> listenersCopy =
+                    new ArrayList<AsyncListenerWrapper>();
+            listenersCopy.addAll(listeners);
+            for (AsyncListenerWrapper listener : listenersCopy) {
+                try {
+                    listener.fireOnError(errorEvent);
+                } catch (IOException ioe) {
+                    log.warn("onError() failed for listener of type [" +
+                            listener.getClass().getName() + "]", ioe);
+                }
+            }
+        }
+
+
+        AtomicBoolean result = new AtomicBoolean();
+        request.getCoyoteRequest().action(ActionCode.ASYNC_IS_ERROR, result);
+        if (result.get()) {
+            // No listener called dispatch() or complete(). This is an error.
+            // SRV.2.3.3.3 (search for "error dispatch")
+            if (servletResponse instanceof HttpServletResponse) {
+                ((HttpServletResponse) servletResponse).setStatus(
+                        HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            }
+
+            Host host = (Host) context.getParent();
+            Valve stdHostValve = host.getPipeline().getBasic();
+            if (stdHostValve instanceof StandardHostValve) {
+                ((StandardHostValve) stdHostValve).throwable(request,
+                        request.getResponse(), t);
+            }
+
+            request.getCoyoteRequest().action(
+                    ActionCode.ASYNC_IS_ERROR, result);
+            if (result.get()) {
+                // Still in the error state. The error page did not call
+                // complete() or dispatch(). Complete the async processing.
+                complete();
             }
         }
     }
diff --git a/java/org/apache/catalina/core/ContainerBase.java b/java/org/apache/catalina/core/ContainerBase.java
index e7fd2ed..e04687f 100644
--- a/java/org/apache/catalina/core/ContainerBase.java
+++ b/java/org/apache/catalina/core/ContainerBase.java
@@ -29,6 +29,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Future;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadFactory;
@@ -176,12 +177,13 @@ public abstract class ContainerBase extends LifecycleMBeanBase
 
 
     /**
-     * The container event listeners for this Container.
+     * The container event listeners for this Container. Implemented as a
+     * CopyOnWriteArrayList since listeners may invoke methods to add/remove
+     * themselves or other listeners and with a ReadWriteLock that would trigger
+     * a deadlock.
      */
-    protected ArrayList<ContainerListener> listeners =
-            new ArrayList<ContainerListener>();
-    protected final ReadWriteLock listenersLock = new ReentrantReadWriteLock();
-
+    protected List<ContainerListener> listeners =
+            new CopyOnWriteArrayList<ContainerListener>();
 
     /**
      * The Loader implementation with which this Container is associated.
@@ -915,14 +917,7 @@ public abstract class ContainerBase extends LifecycleMBeanBase
      */
     @Override
     public void addContainerListener(ContainerListener listener) {
-
-        Lock write = listenersLock.writeLock();
-        write.lock();
-        try {
-            listeners.add(listener);
-        } finally {
-            write.unlock();
-        }
+        listeners.add(listener);
     }
 
 
@@ -979,16 +974,9 @@ public abstract class ContainerBase extends LifecycleMBeanBase
      */
     @Override
     public ContainerListener[] findContainerListeners() {
-
-        Lock read = listenersLock.readLock();
-        read.lock();
-        try {
-            ContainerListener[] results = 
-                new ContainerListener[listeners.size()];
-            return listeners.toArray(results);
-        } finally {
-            read.unlock();
-        }
+        ContainerListener[] results =
+            new ContainerListener[0];
+        return listeners.toArray(results);
     }
 
 
@@ -1066,14 +1054,7 @@ public abstract class ContainerBase extends LifecycleMBeanBase
      */
     @Override
     public void removeContainerListener(ContainerListener listener) {
-
-        Lock write = listenersLock.writeLock();
-        write.lock();
-        try {
-            listeners.remove(listener);
-        } finally {
-            write.unlock();
-        }
+        listeners.remove(listener);
     }
 
 
@@ -1408,30 +1389,13 @@ public abstract class ContainerBase extends LifecycleMBeanBase
     @Override
     public void fireContainerEvent(String type, Object data) {
 
-        /*
-         * Implementation note
-         * There are two options here.
-         * 1) Take a copy of listeners and fire the events outside of the read
-         *    lock
-         * 2) Don't take a copy and fire the events inside the read lock
-         *
-         * Approach 2 has been used here since holding the read lock only
-         * prevents writes and that is preferable to creating lots of array
-         * objects. Since writes occur on start / stop (unless an external
-         * management tool is used) then holding the read lock for a relatively
-         * long time should not be an issue.
-         */
-        Lock read = listenersLock.readLock();
-        read.lock();
-        try {
-            if (listeners.size() < 1)
-                return;
-            ContainerEvent event = new ContainerEvent(this, type, data);
-            for (ContainerListener listener : listeners) {
-                listener.containerEvent(event);
-            }
-        } finally {
-            read.unlock();
+        if (listeners.size() < 1)
+            return;
+
+        ContainerEvent event = new ContainerEvent(this, type, data);
+        // Note for each uses an iterator internally so this is safe
+        for (ContainerListener listener : listeners) {
+            listener.containerEvent(event);
         }
     }
 
diff --git a/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java b/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
index 53f540d..9c7c257 100644
--- a/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
+++ b/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
@@ -218,7 +218,6 @@ public class JreMemoryLeakPreventionListener implements LifecycleListener {
         this.classesToInitialize = classesToInitialize;
     }
     
-    
     @Override
     public void lifecycleEvent(LifecycleEvent event) {
         // Initialise these classes when Tomcat starts
diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties
index 82a12f9..8c77f0f 100644
--- a/java/org/apache/catalina/core/LocalStrings.properties
+++ b/java/org/apache/catalina/core/LocalStrings.properties
@@ -68,6 +68,7 @@ aprListener.tooLateForFIPSMode=Cannot setFIPSMode: SSL has already been initiali
 aprListener.initializedOpenSSL=OpenSSL successfully initialized ({0})
 
 asyncContextImpl.requestEnded=The request associated with the AsyncContext has already completed processing.
+asyncContextImpl.noAsyncDispatcher=The dispatcher returned from the ServletContext does not support asynchronous dispatching
 containerBase.threadedStartFailed=A child container failed during start
 containerBase.threadedStopFailed=A child container failed during stop
 containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process
diff --git a/java/org/apache/catalina/core/NamingContextListener.java b/java/org/apache/catalina/core/NamingContextListener.java
index 527ad6f..f5ac900 100644
--- a/java/org/apache/catalina/core/NamingContextListener.java
+++ b/java/org/apache/catalina/core/NamingContextListener.java
@@ -21,6 +21,7 @@ package org.apache.catalina.core;
 
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.lang.reflect.Constructor;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Collection;
@@ -76,7 +77,7 @@ import org.apache.tomcat.util.res.StringManager;
  * with each context and server.
  *
  * @author Remy Maucherat
- * @version $Id: NamingContextListener.java 1190357 2011-10-28 14:32:44Z markt $
+ * @version $Id: NamingContextListener.java 1407596 2012-11-09 19:33:44Z markt $
  */
 
 public class NamingContextListener
@@ -863,7 +864,11 @@ public class NamingContextListener
                     }
                 }
             } else {
-                logger.error(sm.getString("naming.invalidEnvEntryType", env.getName()));
+                value = constructEnvEntry(env.getType(), env.getValue());
+                if (value == null) {
+                    logger.error(sm.getString(
+                            "naming.invalidEnvEntryType", env.getName()));
+                }
             }
         } catch (NumberFormatException e) {
             logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName()));
@@ -886,6 +891,33 @@ public class NamingContextListener
     }
 
 
+    private Object constructEnvEntry(String type, String value) {
+        try {
+            Class<?> clazz = Class.forName(type);
+            Constructor<?> c = null;
+            try {
+                 c = clazz.getConstructor(String.class);
+                 return c.newInstance(value);
+            } catch (NoSuchMethodException e) {
+                // Ignore
+            }
+
+            if (value.length() != 1) {
+                return null;
+            }
+
+            try {
+                c = clazz.getConstructor(char.class);
+                return c.newInstance(Character.valueOf(value.charAt(0)));
+            } catch (NoSuchMethodException e) {
+                // Ignore
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+        return null;
+    }
+
     /**
      * Set the specified local EJBs in the naming context.
      */
diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java
index d5f5cc6..5fc560d 100644
--- a/java/org/apache/catalina/core/StandardContext.java
+++ b/java/org/apache/catalina/core/StandardContext.java
@@ -127,7 +127,7 @@ import org.apache.tomcat.util.scan.StandardJarScanner;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: StandardContext.java 1350247 2012-06-14 14:04:20Z markt $
+ * @version $Id: StandardContext.java 1355734 2012-06-30 13:24:09Z markt $
  */
 
 public class StandardContext extends ContainerBase
@@ -574,7 +574,8 @@ public class StandardContext extends ContainerBase
     
     /**
      * The status code error pages for this web application, keyed by
-     * HTTP status code (as an Integer).
+     * HTTP status code (as an Integer). Note status code zero is used for the
+     * default error page.
      */
     private HashMap<Integer, ErrorPage> statusPages =
         new HashMap<Integer, ErrorPage>();
diff --git a/java/org/apache/catalina/core/StandardHost.java b/java/org/apache/catalina/core/StandardHost.java
index f54fda1..e96595a 100644
--- a/java/org/apache/catalina/core/StandardHost.java
+++ b/java/org/apache/catalina/core/StandardHost.java
@@ -5,9 +5,9 @@
  * 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.
@@ -46,14 +46,14 @@ import org.apache.tomcat.util.ExceptionUtils;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: StandardHost.java 1343337 2012-05-28 17:50:14Z kkolinko $
+ * @version $Id: StandardHost.java 1382367 2012-09-08 21:11:46Z markt $
  */
 
 public class StandardHost extends ContainerBase implements Host {
 
     private static final org.apache.juli.logging.Log log=
         org.apache.juli.logging.LogFactory.getLog( StandardHost.class );
-    
+
     // ----------------------------------------------------------- Constructors
 
 
@@ -75,7 +75,7 @@ public class StandardHost extends ContainerBase implements Host {
      * The set of aliases for this Host.
      */
     private String[] aliases = new String[0];
-    
+
     private final Object aliasesLock = new Object();
 
 
@@ -132,7 +132,7 @@ public class StandardHost extends ContainerBase implements Host {
 
 
     /**
-     * The Java class name of the default error reporter implementation class 
+     * The Java class name of the default error reporter implementation class
      * for deployed web applications.
      */
     private String errorReportValveClass =
@@ -162,15 +162,15 @@ public class StandardHost extends ContainerBase implements Host {
      */
      private boolean createDirs = true;
 
-     
+
      /**
       * Track the class loaders for the child web applications so memory leaks
       * can be detected.
       */
      private Map<ClassLoader, String> childClassLoaders =
          new WeakHashMap<ClassLoader, String>();
-     
-     
+
+
      /**
       * Any file or directory in {@link #appBase} that this pattern matches will
       * be ignored by the automatic deployment process (both
@@ -179,12 +179,27 @@ public class StandardHost extends ContainerBase implements Host {
      private Pattern deployIgnore = null;
 
 
+    private boolean undeployOldVersions = false;
+
+
     // ------------------------------------------------------------- Properties
 
-     @Override
-     public ExecutorService getStartStopExecutor() {
-         return startStopExecutor;
-     }
+    @Override
+    public boolean getUndeployOldVersions() {
+        return undeployOldVersions;
+    }
+
+
+    @Override
+    public void setUndeployOldVersions(boolean undeployOldVersions) {
+        this.undeployOldVersions = undeployOldVersions;
+    }
+
+
+    @Override
+    public ExecutorService getStartStopExecutor() {
+        return startStopExecutor;
+    }
 
 
     /**
@@ -225,7 +240,7 @@ public class StandardHost extends ContainerBase implements Host {
         return (this.xmlBase);
 
     }
-    
+
 
     /**
      * Set the Xml root for this Host.  This can be an absolute
@@ -264,7 +279,7 @@ public class StandardHost extends ContainerBase implements Host {
     }
 
     /**
-     * Return the value of the auto deploy flag.  If true, it indicates that 
+     * Return the value of the auto deploy flag.  If true, it indicates that
      * this host's child webapps will be dynamically deployed.
      */
     @Override
@@ -277,7 +292,7 @@ public class StandardHost extends ContainerBase implements Host {
 
     /**
      * Set the auto deploy flag value for this host.
-     * 
+     *
      * @param autoDeploy The new auto deploy flag
      */
     @Override
@@ -285,7 +300,7 @@ public class StandardHost extends ContainerBase implements Host {
 
         boolean oldAutoDeploy = this.autoDeploy;
         this.autoDeploy = autoDeploy;
-        support.firePropertyChange("autoDeploy", oldAutoDeploy, 
+        support.firePropertyChange("autoDeploy", oldAutoDeploy,
                                    this.autoDeploy);
 
     }
@@ -348,8 +363,8 @@ public class StandardHost extends ContainerBase implements Host {
 
 
     /**
-     * Return the value of the deploy on startup flag.  If true, it indicates 
-     * that this host's child webapps should be discovered and automatically 
+     * Return the value of the deploy on startup flag.  If true, it indicates
+     * that this host's child webapps should be discovered and automatically
      * deployed at startup time.
      */
     @Override
@@ -362,7 +377,7 @@ public class StandardHost extends ContainerBase implements Host {
 
     /**
      * Set the deploy on startup flag value for this host.
-     * 
+     *
      * @param deployOnStartup The new deploy on startup flag
      */
     @Override
@@ -370,7 +385,7 @@ public class StandardHost extends ContainerBase implements Host {
 
         boolean oldDeployOnStartup = this.deployOnStartup;
         this.deployOnStartup = deployOnStartup;
-        support.firePropertyChange("deployOnStartup", oldDeployOnStartup, 
+        support.firePropertyChange("deployOnStartup", oldDeployOnStartup,
                                    this.deployOnStartup);
 
     }
@@ -416,8 +431,8 @@ public class StandardHost extends ContainerBase implements Host {
         this.copyXML= copyXML;
 
     }
-    
-    
+
+
     /**
      * Return the Java class name of the error report valve class
      * for new web applications.
@@ -440,12 +455,12 @@ public class StandardHost extends ContainerBase implements Host {
         String oldErrorReportValveClassClass = this.errorReportValveClass;
         this.errorReportValveClass = errorReportValveClass;
         support.firePropertyChange("errorReportValveClass",
-                                   oldErrorReportValveClassClass, 
+                                   oldErrorReportValveClassClass,
                                    this.errorReportValveClass);
 
     }
-    
-    
+
+
     /**
      * Return the canonical, fully qualified, name of the virtual host
      * this Container represents.
@@ -529,7 +544,7 @@ public class StandardHost extends ContainerBase implements Host {
     public String getDeployIgnore() {
         if (deployIgnore == null) {
             return null;
-        } 
+        }
         return this.deployIgnore.toString();
     }
 
@@ -564,7 +579,7 @@ public class StandardHost extends ContainerBase implements Host {
             this.deployIgnore = Pattern.compile(deployIgnore);
         }
         support.firePropertyChange("deployIgnore",
-                                   oldDeployIgnore, 
+                                   oldDeployIgnore,
                                    deployIgnore);
     }
 
@@ -636,8 +651,8 @@ public class StandardHost extends ContainerBase implements Host {
             }
         }
     }
-    
-    
+
+
     /**
      * Attempt to identify the contexts that have a class loader memory leak.
      * This is usually triggered on context reload. Note: This method attempts
@@ -645,11 +660,11 @@ public class StandardHost extends ContainerBase implements Host {
      * caution on a production system.
      */
     public String[] findReloadedContextMemoryLeaks() {
-        
+
         System.gc();
-        
+
         List<String> result = new ArrayList<String>();
-        
+
         for (Map.Entry<ClassLoader, String> entry :
                 childClassLoaders.entrySet()) {
             ClassLoader cl = entry.getKey();
@@ -659,7 +674,7 @@ public class StandardHost extends ContainerBase implements Host {
                 }
             }
         }
-        
+
         return result.toArray(new String[result.size()]);
     }
 
@@ -747,7 +762,7 @@ public class StandardHost extends ContainerBase implements Host {
         return (sb.toString());
 
     }
-    
+
     /**
      * Start this component and implement the requirements
      * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
@@ -757,7 +772,7 @@ public class StandardHost extends ContainerBase implements Host {
      */
     @Override
     protected synchronized void startInternal() throws LifecycleException {
-        
+
         // Set error report valve
         String errorValve = getErrorReportValveClass();
         if ((errorValve != null) && (!errorValve.equals(""))) {
@@ -821,5 +836,5 @@ public class StandardHost extends ContainerBase implements Host {
 
         return keyProperties.toString();
     }
-    
+
 }
diff --git a/java/org/apache/catalina/core/StandardHostValve.java b/java/org/apache/catalina/core/StandardHostValve.java
index eefa27b..0724cba 100644
--- a/java/org/apache/catalina/core/StandardHostValve.java
+++ b/java/org/apache/catalina/core/StandardHostValve.java
@@ -53,7 +53,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: StandardHostValve.java 1240845 2012-02-05 21:58:25Z markt $
+ * @version $Id: StandardHostValve.java 1408152 2012-11-11 23:35:41Z markt $
  */
 
 final class StandardHostValve extends ValveBase {
@@ -161,6 +161,9 @@ final class StandardHostValve extends ValveBase {
         // If a request init listener throws an exception, the request is
         // aborted
         boolean asyncAtStart = request.isAsync(); 
+        // An async error page may dispatch to another resource. This flag helps
+        // ensure an infinite error handling loop is not entered
+        boolean errorAtStart = response.isError();
         if (asyncAtStart || context.fireRequestInitEvent(request)) {
 
             // Ask this Context to process this request
@@ -168,29 +171,37 @@ final class StandardHostValve extends ValveBase {
                 context.getPipeline().getFirst().invoke(request, response);
             } catch (Throwable t) {
                 ExceptionUtils.handleThrowable(t);
-                request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
-                throwable(request, response, t);
+                if (errorAtStart) {
+                    container.getLogger().error("Exception Processing " +
+                            request.getRequestURI(), t);
+                } else {
+                    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 (!(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);
+                    if (!errorAtStart) {
+                        // Error page processing
+                        response.setSuspended(false);
     
-                    Throwable t = (Throwable) request.getAttribute(
-                            RequestDispatcher.ERROR_EXCEPTION);
+                        Throwable t = (Throwable) request.getAttribute(
+                                RequestDispatcher.ERROR_EXCEPTION);
     
-                    if (t != null) {
-                        throwable(request, response, t);
-                    } else {
-                        status(request, response);
+                        if (t != null) {
+                            throwable(request, response, t);
+                        } else {
+                            status(request, response);
+                        }
                     }
     
                     context.fireRequestDestroyEvent(request);
@@ -299,6 +310,10 @@ final class StandardHostValve extends ValveBase {
             return;
 
         ErrorPage errorPage = context.findErrorPage(statusCode);
+        if (errorPage == null) {
+            // Look for a default error page
+            errorPage = context.findErrorPage(0);
+        }
         if (errorPage != null) {
             response.setAppCommitted(false);
             request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
@@ -308,11 +323,10 @@ final class StandardHostValve extends ValveBase {
             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);
+            request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
+                    errorPage.getLocation());
+            request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,
+                    DispatcherType.ERROR);
 
 
             Wrapper wrapper = request.getWrapper();
@@ -345,7 +359,7 @@ final class StandardHostValve extends ValveBase {
      * @param throwable The exception that occurred (which possibly wraps
      *  a root cause exception
      */
-    private void throwable(Request request, Response response,
+    protected void throwable(Request request, Response response,
                              Throwable throwable) {
         Context context = request.getContext();
         if (context == null)
@@ -377,11 +391,10 @@ final class StandardHostValve extends ValveBase {
 
         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(Globals.DISPATCHER_REQUEST_PATH_ATTR,
+                    errorPage.getLocation());
+            request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,
+                    DispatcherType.ERROR);
             request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
                     new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
             request.setAttribute(RequestDispatcher.ERROR_MESSAGE,
@@ -449,6 +462,7 @@ final class StandardHostValve extends ValveBase {
             } else {
                 // Reset the response (keeping the real error code and message)
                 response.resetBuffer(true);
+                response.setContentLength(-1);
 
                 rd.forward(request.getRequest(), response.getResponse());
 
diff --git a/java/org/apache/catalina/core/StandardWrapper.java b/java/org/apache/catalina/core/StandardWrapper.java
index 7b34422..efb5e4f 100644
--- a/java/org/apache/catalina/core/StandardWrapper.java
+++ b/java/org/apache/catalina/core/StandardWrapper.java
@@ -77,7 +77,7 @@ import org.apache.tomcat.util.modeler.Registry;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: StandardWrapper.java 1241892 2012-02-08 13:28:05Z markt $
+ * @version $Id: StandardWrapper.java 1360943 2012-07-12 21:07:48Z markt $
  */
 @SuppressWarnings("deprecation") // SingleThreadModel
 public class StandardWrapper extends ContainerBase
@@ -1655,7 +1655,7 @@ public class StandardWrapper extends ContainerBase
      */
     @Override
     public void incrementErrorCount(){
-        swValve.setErrorCount(swValve.getErrorCount() + 1);
+        swValve.incrementErrorCount();
     }
 
     public long getLoadTime() {
diff --git a/java/org/apache/catalina/core/StandardWrapperValve.java b/java/org/apache/catalina/core/StandardWrapperValve.java
index 32a7585..086da9f 100644
--- a/java/org/apache/catalina/core/StandardWrapperValve.java
+++ b/java/org/apache/catalina/core/StandardWrapperValve.java
@@ -47,7 +47,7 @@ import org.apache.tomcat.util.res.StringManager;
  * <code>StandardWrapper</code> container implementation.
  *
  * @author Craig R. McClanahan
- * @version $Id: StandardWrapperValve.java 1301255 2012-03-15 22:47:40Z markt $
+ * @version $Id: StandardWrapperValve.java 1390886 2012-09-27 08:24:49Z markt $
  */
 
 final class StandardWrapperValve
@@ -106,7 +106,7 @@ final class StandardWrapperValve
         Context context = (Context) wrapper.getParent();
         
         // Check for the application being marked unavailable
-        if (!context.getAvailable()) {
+        if (!context.getState().isAvailable()) {
             response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                            sm.getString("standardContext.isUnavailable"));
             unavailable = true;
@@ -175,12 +175,9 @@ final class StandardWrapperValve
         MessageBytes requestPathMB = request.getRequestPathMB();
         DispatcherType dispatcherType = DispatcherType.REQUEST;
         if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC; 
-        request.setAttribute
-            (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-             dispatcherType);
-        request.setAttribute
-            (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
-             requestPathMB);
+        request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
+        request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
+                requestPathMB);
         // Create the filter chain for this request
         ApplicationFilterFactory factory =
             ApplicationFilterFactory.getInstance();
@@ -361,7 +358,8 @@ final class StandardWrapperValve
         Context context = (Context) wrapper.getParent();
 
         // Check for the application being marked unavailable
-        boolean unavailable = !context.getAvailable() || wrapper.isUnavailable();
+        boolean unavailable = !context.getState().isAvailable() ||
+                wrapper.isUnavailable();
         
         // Allocate a servlet instance to process this request
         try {
@@ -385,12 +383,10 @@ final class StandardWrapperValve
         }
 
         MessageBytes requestPathMB = request.getRequestPathMB();
-        request.setAttribute
-            (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
-             DispatcherType.REQUEST);
-        request.setAttribute
-            (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
-             requestPathMB);
+        request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,
+                DispatcherType.REQUEST);
+        request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
+                requestPathMB);
         // Get the current (unchanged) filter chain for this request
         ApplicationFilterChain filterChain = 
             (ApplicationFilterChain) request.getFilterChain();
@@ -522,6 +518,10 @@ final class StandardWrapperValve
         return processingTime;
     }
 
+    /**
+     * Deprecated   unused
+     */
+    @Deprecated
     public void setProcessingTime(long processingTime) {
         this.processingTime = processingTime;
     }
@@ -530,6 +530,10 @@ final class StandardWrapperValve
         return maxTime;
     }
 
+    /**
+     * Deprecated   unused
+     */
+    @Deprecated
     public void setMaxTime(long maxTime) {
         this.maxTime = maxTime;
     }
@@ -538,6 +542,10 @@ final class StandardWrapperValve
         return minTime;
     }
 
+    /**
+     * Deprecated   unused
+     */
+    @Deprecated
     public void setMinTime(long minTime) {
         this.minTime = minTime;
     }
@@ -546,6 +554,10 @@ final class StandardWrapperValve
         return requestCount;
     }
 
+    /**
+     * Deprecated   unused
+     */
+    @Deprecated
     public void setRequestCount(int requestCount) {
         this.requestCount = requestCount;
     }
@@ -554,6 +566,14 @@ final class StandardWrapperValve
         return errorCount;
     }
 
+    public void incrementErrorCount() {
+        errorCount++;
+    }
+
+    /**
+     * Deprecated   unused
+     */
+    @Deprecated
     public void setErrorCount(int errorCount) {
         this.errorCount = errorCount;
     }
diff --git a/java/org/apache/catalina/core/mbeans-descriptors.xml b/java/org/apache/catalina/core/mbeans-descriptors.xml
index 190d50f..fc7f6e4 100644
--- a/java/org/apache/catalina/core/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/core/mbeans-descriptors.xml
@@ -1211,6 +1211,10 @@
                type="java.lang.String"
                writeable="false"/>
       
+    <attribute name="undeployOldVersions"
+               description="Determines if old versions of applications deployed using parallel deployment are automatically undeployed when no longer used. Requires autoDeploy to be enabled."
+               type="boolean"/>
+
     <attribute name="unpackWARs"
                description="Unpack WARs property"
                is="true"
diff --git a/java/org/apache/catalina/deploy/ErrorPage.java b/java/org/apache/catalina/deploy/ErrorPage.java
index 7a30280..a8dffb7 100644
--- a/java/org/apache/catalina/deploy/ErrorPage.java
+++ b/java/org/apache/catalina/deploy/ErrorPage.java
@@ -30,7 +30,7 @@ import org.apache.catalina.util.RequestUtil;
  * deployment descriptor.
  *
  * @author Craig R. McClanahan
- * @version $Id: ErrorPage.java 1001915 2010-09-27 21:32:25Z markt $
+ * @version $Id: ErrorPage.java 1355734 2012-06-30 13:24:09Z markt $
  */
 
 public class ErrorPage implements Serializable {
@@ -41,7 +41,8 @@ public class ErrorPage implements Serializable {
 
 
     /**
-     * The error (status) code for which this error page is active.
+     * The error (status) code for which this error page is active. Note that
+     * status code 0 is used for the default error page.
      */
     private int errorCode = 0;
 
diff --git a/java/org/apache/catalina/deploy/JspPropertyGroup.java b/java/org/apache/catalina/deploy/JspPropertyGroup.java
index 5b00550..3752719 100644
--- a/java/org/apache/catalina/deploy/JspPropertyGroup.java
+++ b/java/org/apache/catalina/deploy/JspPropertyGroup.java
@@ -58,7 +58,7 @@ public class JspPropertyGroup {
         this.pageEncoding = pageEncoding;
     }
     public String getPageEncoding() { return this.pageEncoding; }
-    
+
     private Boolean scriptingInvalid = null;
     public void setScriptingInvalid(String scriptingInvalid) {
         this.scriptingInvalid = Boolean.valueOf(scriptingInvalid);
@@ -71,24 +71,24 @@ public class JspPropertyGroup {
     }
     public Boolean getTrimWhitespace() { return trimWhitespace; }
 
-    private String urlPattern = null;
-    public void setUrlPattern(String urlPattern) {
-        this.urlPattern = urlPattern;
+    private LinkedHashSet<String> urlPattern = new LinkedHashSet<String>();
+    public void addUrlPattern(String urlPattern) {
+        this.urlPattern.add(urlPattern);
     }
-    public String getUrlPattern() { return this.urlPattern; }
-    
+    public Set<String> getUrlPatterns() { return this.urlPattern; }
+
     private String defaultContentType = null;
     public void setDefaultContentType(String defaultContentType) {
         this.defaultContentType = defaultContentType;
     }
     public String getDefaultContentType() { return this.defaultContentType; }
-    
+
     private Integer buffer = null;
     public void setBuffer(String buffer) {
         this.buffer = Integer.valueOf(buffer);
     }
     public Integer getBuffer() { return this.buffer; }
-    
+
     private Boolean errorOnUndeclaredNamespace = null;
     public void setErrorOnUndeclaredNamespace(
             String errorOnUndeclaredNamespace) {
@@ -98,5 +98,4 @@ public class JspPropertyGroup {
     public Boolean getErrorOnUndeclaredNamespace() {
         return this.errorOnUndeclaredNamespace;
     }
-    
 }
diff --git a/java/org/apache/catalina/deploy/WebXml.java b/java/org/apache/catalina/deploy/WebXml.java
index f65d3a4..965afc3 100644
--- a/java/org/apache/catalina/deploy/WebXml.java
+++ b/java/org/apache/catalina/deploy/WebXml.java
@@ -5,9 +5,9 @@
  * 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.
@@ -26,7 +26,6 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -53,10 +52,10 @@ import org.apache.tomcat.util.res.StringManager;
  * StandardContext will check validity of values (eg URL formats etc)
  */
 public class WebXml {
-    
+
     protected static final String ORDER_OTHERS =
         "org.apache.catalina.order.others";
-    
+
     private static final StringManager sm =
         StringManager.getManager(Constants.Package);
 
@@ -107,7 +106,7 @@ public class WebXml {
         after.add(ORDER_OTHERS);
     }
     public Set<String> getAfterOrdering() { return after; }
-    
+
     private Set<String> before = new LinkedHashSet<String>();
     public void addBeforeOrdering(String fragmentName) {
         before.add(fragmentName);
@@ -122,7 +121,7 @@ public class WebXml {
     public Set<String> getBeforeOrdering() { return before; }
 
     // Common elements and attributes
-    
+
     // Required attribute of web-app element
     public String getVersion() {
         StringBuilder sb = new StringBuilder(3);
@@ -137,7 +136,7 @@ public class WebXml {
      */
     public void setVersion(String version) {
         if (version == null) return;
-        
+
         // Update major and minor version
         // Expected format is n.n - allow for any number of digits just in case
         String major = null;
@@ -161,7 +160,7 @@ public class WebXml {
                 majorVersion = 0;
             }
         }
-        
+
         if (minor == null || minor.length() == 0) {
             minorVersion = 0;
         } else {
@@ -218,13 +217,13 @@ public class WebXml {
             log.warn(sm.getString("webxml.unrecognisedPublicId", publicId));
         }
     }
-    
+
     // Optional metadata-complete attribute
     private boolean metadataComplete = false;
     public boolean isMetadataComplete() { return metadataComplete; }
     public void setMetadataComplete(boolean metadataComplete) {
         this.metadataComplete = metadataComplete; }
-    
+
     // Optional name element
     private String name = null;
     public String getName() { return name; }
@@ -243,7 +242,7 @@ public class WebXml {
     private int minorVersion = 0;
     public int getMajorVersion() { return majorVersion; }
     public int getMinorVersion() { return minorVersion; }
-    
+
     // web-app elements
     // TODO: Ignored elements:
     // - description
@@ -255,14 +254,14 @@ public class WebXml {
     public void setDisplayName(String displayName) {
         this.displayName = displayName;
     }
-    
+
     // distributable
     private boolean distributable = false;
     public boolean isDistributable() { return distributable; }
     public void setDistributable(boolean distributable) {
         this.distributable = distributable;
     }
-    
+
     // context-param
     // TODO: description (multiple with language) is ignored
     private Map<String,String> contextParams = new HashMap<String,String>();
@@ -270,7 +269,7 @@ public class WebXml {
         contextParams.put(param, value);
     }
     public Map<String,String> getContextParams() { return contextParams; }
-    
+
     // filter
     // TODO: Should support multiple description elements with language
     // TODO: Should support multiple display-name elements with language
@@ -288,7 +287,7 @@ public class WebXml {
         filters.put(filter.getFilterName(), filter);
     }
     public Map<String,FilterDef> getFilters() { return filters; }
-    
+
     // filter-mapping
     private Set<FilterMap> filterMaps = new LinkedHashSet<FilterMap>();
     private Set<String> filterMappingNames = new HashSet<String>();
@@ -297,7 +296,7 @@ public class WebXml {
         filterMappingNames.add(filterMap.getFilterName());
     }
     public Set<FilterMap> getFilterMappings() { return filterMaps; }
-    
+
     // listener
     // TODO: description (multiple with language) is ignored
     // TODO: display-name (multiple with language) is ignored
@@ -307,7 +306,7 @@ public class WebXml {
         listeners.add(className);
     }
     public Set<String> getListeners() { return listeners; }
-    
+
     // servlet
     // TODO: description (multiple with language) is ignored
     // TODO: display-name (multiple with language) is ignored
@@ -322,7 +321,7 @@ public class WebXml {
         }
     }
     public Map<String,ServletDef> getServlets() { return servlets; }
-    
+
     // servlet-mapping
     private Map<String,String> servletMappings = new HashMap<String,String>();
     private Set<String> servletMappingNames = new HashSet<String>();
@@ -331,7 +330,7 @@ public class WebXml {
         servletMappingNames.add(servletName);
     }
     public Map<String,String> getServletMappings() { return servletMappings; }
-    
+
     // session-config
     // Digester will check there is only one of these
     private SessionConfig sessionConfig = new SessionConfig();
@@ -339,14 +338,14 @@ public class WebXml {
         this.sessionConfig = sessionConfig;
     }
     public SessionConfig getSessionConfig() { return sessionConfig; }
-    
+
     // mime-mapping
     private Map<String,String> mimeMappings = new HashMap<String,String>();
     public void addMimeMapping(String extension, String mimeType) {
         mimeMappings.put(extension, mimeType);
     }
     public Map<String,String> getMimeMappings() { return mimeMappings; }
-    
+
     // welcome-file-list merge control
     private boolean replaceWelcomeFiles = false;
     private boolean alwaysAddWelcomeFiles = true;
@@ -375,14 +374,14 @@ public class WebXml {
         welcomeFiles.add(welcomeFile);
     }
     public Set<String> getWelcomeFiles() { return welcomeFiles; }
-    
+
     // error-page
     private Map<String,ErrorPage> errorPages = new HashMap<String,ErrorPage>();
     public void addErrorPage(ErrorPage errorPage) {
         errorPages.put(errorPage.getName(), errorPage);
     }
     public Map<String,ErrorPage> getErrorPages() { return errorPages; }
-    
+
     // Digester will check there is only one jsp-config
     // jsp-config/taglib or taglib (2.3 and earlier)
     private Map<String,String> taglibs = new HashMap<String,String>();
@@ -395,7 +394,7 @@ public class WebXml {
         taglibs.put(uri, location);
     }
     public Map<String,String> getTaglibs() { return taglibs; }
-    
+
     // jsp-config/jsp-property-group
     private Set<JspPropertyGroup> jspPropertyGroups =
         new LinkedHashSet<JspPropertyGroup>();
@@ -417,7 +416,7 @@ public class WebXml {
     public Set<SecurityConstraint> getSecurityConstraints() {
         return securityConstraints;
     }
-    
+
     // login-config
     // Digester will check there is only one of these
     private LoginConfig loginConfig = null;
@@ -425,7 +424,7 @@ public class WebXml {
         this.loginConfig = loginConfig;
     }
     public LoginConfig getLoginConfig() { return loginConfig; }
-    
+
     // security-role
     // TODO: description (multiple with language) is ignored
     private Set<String> securityRoles = new HashSet<String>();
@@ -433,7 +432,7 @@ public class WebXml {
         securityRoles.add(securityRole);
     }
     public Set<String> getSecurityRoles() { return securityRoles; }
-    
+
     // env-entry
     // TODO: Should support multiple description elements with language
     private Map<String,ContextEnvironment> envEntries =
@@ -448,7 +447,7 @@ public class WebXml {
         envEntries.put(envEntry.getName(),envEntry);
     }
     public Map<String,ContextEnvironment> getEnvEntries() { return envEntries; }
-    
+
     // ejb-ref
     // TODO: Should support multiple description elements with language
     private Map<String,ContextEjb> ejbRefs = new HashMap<String,ContextEjb>();
@@ -456,7 +455,7 @@ public class WebXml {
         ejbRefs.put(ejbRef.getName(),ejbRef);
     }
     public Map<String,ContextEjb> getEjbRefs() { return ejbRefs; }
-    
+
     // ejb-local-ref
     // TODO: Should support multiple description elements with language
     private Map<String,ContextLocalEjb> ejbLocalRefs =
@@ -467,7 +466,7 @@ public class WebXml {
     public Map<String,ContextLocalEjb> getEjbLocalRefs() {
         return ejbLocalRefs;
     }
-    
+
     // service-ref
     // TODO: Should support multiple description elements with language
     // TODO: Should support multiple display-names elements with language
@@ -478,7 +477,7 @@ public class WebXml {
         serviceRefs.put(serviceRef.getName(), serviceRef);
     }
     public Map<String,ContextService> getServiceRefs() { return serviceRefs; }
-    
+
     // resource-ref
     // TODO: Should support multiple description elements with language
     private Map<String,ContextResource> resourceRefs =
@@ -495,7 +494,7 @@ public class WebXml {
     public Map<String,ContextResource> getResourceRefs() {
         return resourceRefs;
     }
-    
+
     // resource-env-ref
     // TODO: Should support multiple description elements with language
     private Map<String,ContextResourceEnvRef> resourceEnvRefs =
@@ -512,7 +511,7 @@ public class WebXml {
     public Map<String,ContextResourceEnvRef> getResourceEnvRefs() {
         return resourceEnvRefs;
     }
-    
+
     // message-destination-ref
     // TODO: Should support multiple description elements with language
     private Map<String,MessageDestinationRef> messageDestinationRefs =
@@ -533,7 +532,7 @@ public class WebXml {
     public Map<String,MessageDestinationRef> getMessageDestinationRefs() {
         return messageDestinationRefs;
     }
-    
+
     // message-destination
     // TODO: Should support multiple description elements with language
     // TODO: Should support multiple display-names elements with language
@@ -556,8 +555,8 @@ public class WebXml {
     public Map<String,MessageDestination> getMessageDestinations() {
         return messageDestinations;
     }
-    
-    // locale-encoging-mapping-list
+
+    // locale-encoding-mapping-list
     private Map<String,String> localeEncodingMappings =
         new HashMap<String,String>();
     public void addLocaleEncodingMapping(String locale, String encoding) {
@@ -566,10 +565,10 @@ public class WebXml {
     public Map<String,String> getLocalEncodingMappings() {
         return localeEncodingMappings;
     }
-    
+
 
     // Attributes not defined in web.xml or web-fragment.xml
-    
+
     // URL of JAR / exploded JAR for this web-fragment
     private URL uRL = null;
     public void setURL(URL url) { this.uRL = url; }
@@ -585,51 +584,52 @@ public class WebXml {
         buf.append(getURL());
         return buf.toString();
     }
-    
+
     private static final String INDENT2 = "  ";
     private static final String INDENT4 = "    ";
     private static final String INDENT6 = "      ";
-    
+
     /**
      * Generate a web.xml in String form that matches the representation stored
      * in this object.
-     * 
+     *
      * @return The complete contents of web.xml as a String
      */
     public String toXml() {
         StringBuilder sb = new StringBuilder(2048);
-        
+
         // TODO - Various, icon, description etc elements are skipped - mainly
         //        because they are ignored when web.xml is parsed - see above
 
         // Declaration
         sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
-        
+
         // Root element
         sb.append("<web-app xmlns=\"http://java.sun.com/xml/ns/javaee\"\n");
         sb.append("         xmlns:xsi=");
         sb.append("\"http://www.w3.org/2001/XMLSchema-instance\"\n");
         sb.append("         xsi:schemaLocation=");
-        sb.append("\"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\"\n");
+        sb.append("\"http://java.sun.com/xml/ns/javaee" +
+                  " http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\"\n");
         sb.append("         version=\"");
         sb.append(getVersion());
         sb.append("\"\n");
         sb.append("         metadata-complete=\"true\">\n\n");
 
         appendElement(sb, INDENT2, "display-name", displayName);
-        
+
         if (isDistributable()) {
             sb.append("  <distributable/>\n\n");
         }
-        
+
         for (Map.Entry<String, String> entry : contextParams.entrySet()) {
             sb.append("  <context-param>\n");
             appendElement(sb, INDENT4, "param-name", entry.getKey());
-            appendElement(sb, INDENT4, "param-valuee", entry.getValue());
+            appendElement(sb, INDENT4, "param-value", entry.getValue());
             sb.append("  </context-param>\n");
         }
         sb.append('\n');
-        
+
         for (Map.Entry<String, FilterDef> entry : filters.entrySet()) {
             FilterDef filterDef = entry.getValue();
             sb.append("  <filter>\n");
@@ -744,7 +744,7 @@ public class WebXml {
             sb.append("  </servlet-mapping>\n");
         }
         sb.append('\n');
-        
+
         if (sessionConfig != null) {
             sb.append("  <session-config>\n");
             appendElement(sb, INDENT4, "session-timeout",
@@ -769,7 +769,7 @@ public class WebXml {
             }
             sb.append("  </session-config>\n\n");
         }
-        
+
         for (Map.Entry<String, String> entry : mimeMappings.entrySet()) {
             sb.append("  <mime-mapping>\n");
             appendElement(sb, INDENT4, "extension", entry.getKey());
@@ -777,7 +777,7 @@ public class WebXml {
             sb.append("  </mime-mapping>\n");
         }
         sb.append('\n');
-        
+
         if (welcomeFiles.size() > 0) {
             sb.append("  <welcome-file-list>\n");
             for (String welcomeFile : welcomeFiles) {
@@ -785,7 +785,7 @@ public class WebXml {
             }
             sb.append("  </welcome-file-list>\n\n");
         }
-        
+
         for (ErrorPage errorPage : errorPages.values()) {
             sb.append("  <error-page>\n");
             if (errorPage.getExceptionType() == null) {
@@ -810,19 +810,21 @@ public class WebXml {
             }
             for (JspPropertyGroup jpg : jspPropertyGroups) {
                 sb.append("    <jsp-property-group>\n");
-                appendElement(sb, INDENT6, "url-pattern", jpg.getUrlPattern());
+                for (String urlPattern : jpg.getUrlPatterns()) {
+                    appendElement(sb, INDENT6, "url-pattern", urlPattern);
+                }
                 appendElement(sb, INDENT6, "el-ignored", jpg.getElIgnored());
-                appendElement(sb, INDENT6, "scripting-invalid",
-                        jpg.getScriptingInvalid());
                 appendElement(sb, INDENT6, "page-encoding",
                         jpg.getPageEncoding());
+                appendElement(sb, INDENT6, "scripting-invalid",
+                        jpg.getScriptingInvalid());
+                appendElement(sb, INDENT6, "is-xml", jpg.getIsXml());
                 for (String prelude : jpg.getIncludePreludes()) {
                     appendElement(sb, INDENT6, "include-prelude", prelude);
                 }
                 for (String coda : jpg.getIncludeCodas()) {
                     appendElement(sb, INDENT6, "include-coda", coda);
                 }
-                appendElement(sb, INDENT6, "is-xml", jpg.getIsXml());
                 appendElement(sb, INDENT6, "deferred-syntax-allowed-as-literal",
                         jpg.getDeferredSyntax());
                 appendElement(sb, INDENT6, "trim-directive-whitespaces",
@@ -836,7 +838,7 @@ public class WebXml {
             }
             sb.append("  </jsp-config>\n\n");
         }
-        
+
         for (SecurityConstraint constraint : securityConstraints) {
             sb.append("  <security-constraint>\n");
             appendElement(sb, INDENT4, "display-name",
@@ -892,13 +894,13 @@ public class WebXml {
             }
             sb.append("  </login-config>\n\n");
         }
-        
+
         for (String roleName : securityRoles) {
             sb.append("  <security-role>\n");
             appendElement(sb, INDENT4, "role-name", roleName);
             sb.append("  </security-role>\n");
         }
-        
+
         for (ContextEnvironment envEntry : envEntries.values()) {
             sb.append("  <env-entry>\n");
             appendElement(sb, INDENT4, "description",
@@ -964,7 +966,7 @@ public class WebXml {
             sb.append("  </ejb-local-ref>\n");
         }
         sb.append('\n');
-        
+
         for (ContextService serviceRef : serviceRefs.values()) {
             sb.append("  <service-ref>\n");
             appendElement(sb, INDENT4, "description",
@@ -1020,7 +1022,7 @@ public class WebXml {
             sb.append("  </service-ref>\n");
         }
         sb.append('\n');
-        
+
         for (ContextResource resourceRef : resourceRefs.values()) {
             sb.append("  <resource-ref>\n");
             appendElement(sb, INDENT4, "description",
@@ -1167,7 +1169,7 @@ public class WebXml {
 
     /**
      * Configure a {@link Context} using the stored web.xml representation.
-     *  
+     *
      * @param context   The context to be configured
      */
     public void configureContext(Context context) {
@@ -1179,7 +1181,7 @@ public class WebXml {
         // Everything else in order
         context.setEffectiveMajorVersion(getMajorVersion());
         context.setEffectiveMinorVersion(getMinorVersion());
-        
+
         for (Entry<String, String> entry : contextParams.entrySet()) {
             context.addParameter(entry.getKey(), entry.getValue());
         }
@@ -1228,7 +1230,7 @@ public class WebXml {
         }
 
         // messageDestinations were ignored in Tomcat 6, so ignore here
-        
+
         context.setIgnoreAnnotations(metadataComplete);
         for (Entry<String, String> entry : mimeMappings.entrySet()) {
             context.addMimeMapping(entry.getKey(), entry.getValue());
@@ -1254,7 +1256,7 @@ public class WebXml {
             // Description is ignored
             // Display name is ignored
             // Icons are ignored
-            
+
             // jsp-file gets passed to the JSP Servlet as an init-param
 
             if (servlet.getLoadOnStartup() != null) {
@@ -1264,7 +1266,7 @@ public class WebXml {
                 wrapper.setEnabled(servlet.getEnabled().booleanValue());
             }
             wrapper.setName(servlet.getServletName());
-            Map<String,String> params = servlet.getParameterMap(); 
+            Map<String,String> params = servlet.getParameterMap();
             for (Entry<String, String> entry : params.entrySet()) {
                 wrapper.addInitParameter(entry.getKey(), entry.getValue());
             }
@@ -1331,13 +1333,13 @@ public class WebXml {
                     entry.getValue(), entry.getKey());
             context.getJspConfigDescriptor().getTaglibs().add(descriptor);
         }
-        
+
         // Context doesn't use version directly
-        
+
         for (String welcomeFile : welcomeFiles) {
             /*
              * The following will result in a welcome file of "" so don't add
-             * that to the context 
+             * that to the context
              * <welcome-file-list>
              *   <welcome-file/>
              * </welcome-file-list>
@@ -1354,19 +1356,23 @@ public class WebXml {
                 jspServletName = "jsp";
             }
             if (context.findChild(jspServletName) != null) {
-                context.addServletMapping(jspPropertyGroup.getUrlPattern(),
-                        jspServletName, true);
+                for (String urlPattern : jspPropertyGroup.getUrlPatterns()) {
+                    context.addServletMapping(urlPattern, jspServletName, true);
+                }
             } else {
-                if(log.isDebugEnabled())
-                    log.debug("Skiping " + jspPropertyGroup.getUrlPattern() +
-                            " , no servlet " + jspServletName);
+                if(log.isDebugEnabled()) {
+                    for (String urlPattern : jspPropertyGroup.getUrlPatterns()) {
+                        log.debug("Skiping " + urlPattern + " , no servlet " +
+                                jspServletName);
+                    }
+                }
             }
         }
     }
-    
+
     /**
      * Merge the supplied web fragments into this main web.xml.
-     * 
+     *
      * @param fragments     The fragments to merge in
      * @return <code>true</code> if merge is successful, else
      *         <code>false</code>
@@ -1374,7 +1380,7 @@ public class WebXml {
     public boolean merge(Set<WebXml> fragments) {
         // As far as possible, process in alphabetical order so it is easy to
         // check everything is present
-        
+
         // Merge rules vary from element to element. See SRV.8.2.3
 
         WebXml temp = new WebXml();
@@ -1389,7 +1395,7 @@ public class WebXml {
 
         if (displayName == null) {
             for (WebXml fragment : fragments) {
-                String value = fragment.getDisplayName(); 
+                String value = fragment.getDisplayName();
                 if (value != null) {
                     if (temp.getDisplayName() == null) {
                         temp.setDisplayName(value);
@@ -1477,7 +1483,7 @@ public class WebXml {
                                     entry.getKey(),
                                     fragment.getName(),
                                     fragment.getURL()));
-    
+
                             return false;
                         }
                     } else {
@@ -1609,7 +1615,7 @@ public class WebXml {
                 }
             }
         }
-        
+
         // Add fragment mappings
         for (Map.Entry<String,String> mapping : servletMappingsToAdd) {
             addServletMapping(mapping.getKey(), mapping.getValue());
@@ -1630,7 +1636,7 @@ public class WebXml {
                                     entry.getKey(),
                                     fragment.getName(),
                                     fragment.getURL()));
-    
+
                             return false;
                         }
                     } else {
@@ -1640,7 +1646,7 @@ public class WebXml {
             }
         }
         servlets.putAll(temp.getServlets());
-        
+
         if (sessionConfig.getSessionTimeout() == null) {
             for (WebXml fragment : fragments) {
                 Integer value = fragment.getSessionConfig().getSessionTimeout();
@@ -1664,7 +1670,7 @@ public class WebXml {
                         temp.getSessionConfig().getSessionTimeout().toString());
             }
         }
-        
+
         if (sessionConfig.getCookieName() == null) {
             for (WebXml fragment : fragments) {
                 String value = fragment.getSessionConfig().getCookieName();
@@ -1841,7 +1847,7 @@ public class WebXml {
             sessionConfig.getSessionTrackingModes().addAll(
                     temp.getSessionConfig().getSessionTrackingModes());
         }
-        
+
         for (WebXml fragment : fragments) {
             if (!mergeMap(fragment.getTaglibs(), taglibs,
                     temp.getTaglibs(), fragment, "Taglibs")) {
@@ -1860,7 +1866,7 @@ public class WebXml {
 
         return true;
     }
-    
+
     private static <T extends ResourceBase> boolean mergeResourceMap(
             Map<String, T> fragmentResources, Map<String, T> mainResources,
             Map<String, T> tempResources, WebXml fragment) {
@@ -1883,12 +1889,12 @@ public class WebXml {
                     }
                 } else {
                     tempResources.put(resourceName, resource);
-                } 
+                }
             }
         }
         return true;
     }
-    
+
     private static <T> boolean mergeMap(Map<String,T> fragmentMap,
             Map<String,T> mainMap, Map<String,T> tempMap, WebXml fragment,
             String mapName) {
@@ -1915,7 +1921,7 @@ public class WebXml {
         }
         return true;
     }
-    
+
     private static boolean mergeFilter(FilterDef src, FilterDef dest,
             boolean failOnConflict) {
         if (dest.getAsyncSupported() == null) {
@@ -1935,7 +1941,7 @@ public class WebXml {
                 return false;
             }
         }
-        
+
         for (Map.Entry<String,String> srcEntry :
                 src.getParameterMap().entrySet()) {
             if (dest.getParameterMap().containsKey(srcEntry.getKey())) {
@@ -1949,7 +1955,7 @@ public class WebXml {
         }
         return true;
     }
-    
+
     private static boolean mergeServlet(ServletDef src, ServletDef dest,
             boolean failOnConflict) {
         // These tests should be unnecessary...
@@ -1959,8 +1965,8 @@ public class WebXml {
         if (src.getServletClass() != null && src.getJspFile() != null) {
             return false;
         }
-        
-        
+
+
         if (dest.getServletClass() == null && dest.getJspFile() == null) {
             dest.setServletClass(src.getServletClass());
             dest.setJspFile(src.getJspFile());
@@ -1976,12 +1982,12 @@ public class WebXml {
                 return false;
             }
         }
-        
+
         // Additive
         for (SecurityRoleRef securityRoleRef : src.getSecurityRoleRefs()) {
             dest.addSecurityRoleRef(securityRoleRef);
         }
-        
+
         if (dest.getLoadOnStartup() == null) {
             if (src.getLoadOnStartup() != null) {
                 dest.setLoadOnStartup(src.getLoadOnStartup().toString());
@@ -1992,7 +1998,7 @@ public class WebXml {
                 return false;
             }
         }
-        
+
         if (dest.getEnabled() == null) {
             if (src.getEnabled() != null) {
                 dest.setEnabled(src.getEnabled().toString());
@@ -2003,7 +2009,7 @@ public class WebXml {
                 return false;
             }
         }
-        
+
         for (Map.Entry<String,String> srcEntry :
                 src.getParameterMap().entrySet()) {
             if (dest.getParameterMap().containsKey(srcEntry.getKey())) {
@@ -2015,14 +2021,14 @@ public class WebXml {
                 dest.addInitParameter(srcEntry.getKey(), srcEntry.getValue());
             }
         }
-        
+
         if (dest.getMultipartDef() == null) {
             dest.setMultipartDef(src.getMultipartDef());
         } else if (src.getMultipartDef() != null) {
             return mergeMultipartDef(src.getMultipartDef(),
                     dest.getMultipartDef(), failOnConflict);
         }
-        
+
         if (dest.getAsyncSupported() == null) {
             if (src.getAsyncSupported() != null) {
                 dest.setAsyncSupported(src.getAsyncSupported().toString());
@@ -2033,7 +2039,7 @@ public class WebXml {
                 return false;
             }
         }
-        
+
         return true;
     }
 
@@ -2080,13 +2086,13 @@ public class WebXml {
 
         return true;
     }
-    
-    
+
+
     /**
      * Generates the sub-set of the web-fragment.xml files to be processed in
      * the order that the fragments must be processed as per the rules in the
      * Servlet spec.
-     * 
+     *
      * @param application   The application web.xml file
      * @param fragments     The map of fragment names to web fragments
      * @return Ordered list of web-fragment.xml files to process
@@ -2095,14 +2101,14 @@ public class WebXml {
             Map<String,WebXml> fragments) {
 
         Set<WebXml> orderedFragments = new LinkedHashSet<WebXml>();
-        
+
         boolean absoluteOrdering =
             (application.getAbsoluteOrdering() != null);
-        
+
         if (absoluteOrdering) {
             // Only those fragments listed should be processed
             Set<String> requestedOrder = application.getAbsoluteOrdering();
-            
+
             for (String requestedName : requestedOrder) {
                 if (WebXml.ORDER_OTHERS.equals(requestedName)) {
                     // Add all fragments not named explicitly at this point
@@ -2124,75 +2130,152 @@ public class WebXml {
                 }
             }
         } else {
-            List<String> order = new LinkedList<String>();
-            // Start by adding all fragments - order doesn't matter
-            order.addAll(fragments.keySet());
-            
-            // Now go through and move elements to start/end depending on if
-            // they specify others
+            // Stage 1. Make all dependencies bi-directional - this makes the
+            //          next stage simpler.
             for (WebXml fragment : fragments.values()) {
-                String name = fragment.getName();
-                if (fragment.getBeforeOrdering().contains(WebXml.ORDER_OTHERS)) {
-                    // Move to beginning
-                    order.remove(name);
-                    order.add(0, name);
-                } else if (fragment.getAfterOrdering().contains(WebXml.ORDER_OTHERS)) {
-                    // Move to end
-                    order.remove(name);
-                    order.add(name);
-                }
-            }
-            
-            // Now apply remaining ordering
-            for (WebXml fragment : fragments.values()) {
-                String name = fragment.getName();
-                for (String before : fragment.getBeforeOrdering()) {
-                    if (!before.equals(WebXml.ORDER_OTHERS) &&
-                            order.contains(before) &&
-                            order.indexOf(before) < order.indexOf(name)) {
-                        order.remove(name);
-                        order.add(order.indexOf(before), name);
+                Iterator<String> before =
+                        fragment.getBeforeOrdering().iterator();
+                while (before.hasNext()) {
+                    String beforeEntry = before.next();
+                    if (!beforeEntry.equals(ORDER_OTHERS)) {
+                        WebXml beforeFragment = fragments.get(beforeEntry);
+                        if (beforeFragment == null) {
+                            before.remove();
+                        } else {
+                            beforeFragment.addAfterOrdering(fragment.getName());
+                        }
                     }
                 }
-                for (String after : fragment.getAfterOrdering()) {
-                    if (!after.equals(WebXml.ORDER_OTHERS) &&
-                            order.contains(after) &&
-                            order.indexOf(after) > order.indexOf(name)) {
-                        order.remove(name);
-                        order.add(order.indexOf(after) + 1, name);
+                Iterator<String> after = fragment.getAfterOrdering().iterator();
+                while (after.hasNext()) {
+                    String afterEntry = after.next();
+                    if (!afterEntry.equals(ORDER_OTHERS)) {
+                        WebXml afterFragment = fragments.get(afterEntry);
+                        if (afterFragment == null) {
+                            after.remove();
+                        } else {
+                            afterFragment.addBeforeOrdering(fragment.getName());
+                        }
                     }
                 }
             }
-            
-            // Finally check ordering was applied correctly - if there are
-            // errors then that indicates circular references
+
+            // Stage 2. Make all fragments that are implicitly before/after
+            //          others explicitly so. This is iterative so the next
+            //          stage doesn't have to be.
             for (WebXml fragment : fragments.values()) {
-                String name = fragment.getName();
-                for (String before : fragment.getBeforeOrdering()) {
-                    if (!before.equals(WebXml.ORDER_OTHERS) &&
-                            order.contains(before) &&
-                            order.indexOf(before) < order.indexOf(name)) {
-                        throw new IllegalArgumentException(
-                                sm.getString("webXml.mergeConflictOrder"));
-                    }
+                if (fragment.getBeforeOrdering().contains(ORDER_OTHERS)) {
+                    makeBeforeOthersExplicit(fragment.getAfterOrdering(), fragments);
                 }
-                for (String after : fragment.getAfterOrdering()) {
-                    if (!after.equals(WebXml.ORDER_OTHERS) &&
-                            order.contains(after) &&
-                            order.indexOf(after) > order.indexOf(name)) {
-                        throw new IllegalArgumentException(
-                                sm.getString("webXml.mergeConflictOrder"));
-                    }
+                if (fragment.getAfterOrdering().contains(ORDER_OTHERS)) {
+                    makeAfterOthersExplicit(fragment.getBeforeOrdering(), fragments);
                 }
             }
-            
-            // Build the ordered list
-            for (String name : order) {
-                orderedFragments.add(fragments.get(name));
+
+            // Stage 3. Separate into three groups
+            Set<WebXml> beforeSet = new HashSet<WebXml>();
+            Set<WebXml> othersSet = new HashSet<WebXml>();
+            Set<WebXml> afterSet = new HashSet<WebXml>();
+
+            for (WebXml fragment : fragments.values()) {
+                if (fragment.getBeforeOrdering().contains(ORDER_OTHERS)) {
+                    beforeSet.add(fragment);
+                    fragment.getBeforeOrdering().remove(ORDER_OTHERS);
+                } else if (fragment.getAfterOrdering().contains(ORDER_OTHERS)) {
+                    afterSet.add(fragment);
+                    fragment.getAfterOrdering().remove(ORDER_OTHERS);
+                } else {
+                    othersSet.add(fragment);
+                }
             }
+
+            // Stage 4. Decouple the groups so the ordering requirements for
+            //          each fragment in the group only refer to other fragments
+            //          in the group. Ordering requirements outside the group
+            //          will be handled by processing the groups in order.
+            //          Note: Only after ordering requirements are considered.
+            //                This is OK because of the processing in stage 1.
+            decoupleOtherGroups(beforeSet);
+            decoupleOtherGroups(othersSet);
+            decoupleOtherGroups(afterSet);
+
+            // Stage 5. Order each group
+            //          Note: Only after ordering requirements are considered.
+            //                This is OK because of the processing in stage 1.
+            orderFragments(orderedFragments, beforeSet);
+            orderFragments(orderedFragments, othersSet);
+            orderFragments(orderedFragments, afterSet);
         }
-        
+
         return orderedFragments;
     }
 
-}    
+    private static void decoupleOtherGroups(Set<WebXml> group) {
+        Set<String> names = new HashSet<String>();
+        for (WebXml fragment : group) {
+            names.add(fragment.getName());
+        }
+        for (WebXml fragment : group) {
+            Iterator<String> after = fragment.getAfterOrdering().iterator();
+            while (after.hasNext()) {
+                String entry = after.next();
+                if (!names.contains(entry)) {
+                    after.remove();
+                }
+            }
+        }
+    }
+    private static void orderFragments(Set<WebXml> orderedFragments,
+            Set<WebXml> unordered) {
+        Set<WebXml> addedThisRound = new HashSet<WebXml>();
+        Set<WebXml> addedLastRound = new HashSet<WebXml>();
+        while (unordered.size() > 0) {
+            Iterator<WebXml> source = unordered.iterator();
+            while (source.hasNext()) {
+                WebXml fragment = source.next();
+                for (WebXml toRemove : addedLastRound) {
+                    fragment.getAfterOrdering().remove(toRemove.getName());
+                }
+                if (fragment.getAfterOrdering().isEmpty()) {
+                    addedThisRound.add(fragment);
+                    orderedFragments.add(fragment);
+                    source.remove();
+                }
+            }
+            if (addedThisRound.size() == 0) {
+                // Circular
+                throw new IllegalArgumentException(
+                        sm.getString("webXml.mergeConflictOrder"));
+            }
+            addedLastRound.clear();
+            addedLastRound.addAll(addedThisRound);
+            addedThisRound.clear();
+        }
+    }
+
+    private static void makeBeforeOthersExplicit(Set<String> beforeOrdering,
+            Map<String, WebXml> fragments) {
+        for (String before : beforeOrdering) {
+            if (!before.equals(ORDER_OTHERS)) {
+                WebXml webXml = fragments.get(before);
+                if (!webXml.getBeforeOrdering().contains(ORDER_OTHERS)) {
+                    webXml.addBeforeOrderingOthers();
+                    makeBeforeOthersExplicit(webXml.getAfterOrdering(), fragments);
+                }
+            }
+        }
+    }
+
+    private static void makeAfterOthersExplicit(Set<String> afterOrdering,
+            Map<String, WebXml> fragments) {
+        for (String after : afterOrdering) {
+            if (!after.equals(ORDER_OTHERS)) {
+                WebXml webXml = fragments.get(after);
+                if (!webXml.getAfterOrdering().contains(ORDER_OTHERS)) {
+                    webXml.addAfterOrderingOthers();
+                    makeAfterOthersExplicit(webXml.getBeforeOrdering(), fragments);
+                }
+            }
+        }
+    }
+}
diff --git a/java/org/apache/catalina/filters/CsrfPreventionFilter.java b/java/org/apache/catalina/filters/CsrfPreventionFilter.java
index 3dd578f..9df50d8 100644
--- a/java/org/apache/catalina/filters/CsrfPreventionFilter.java
+++ b/java/org/apache/catalina/filters/CsrfPreventionFilter.java
@@ -33,6 +33,7 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponseWrapper;
+import javax.servlet.http.HttpSession;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -56,6 +57,8 @@ public class CsrfPreventionFilter extends FilterBase {
     
     private Random randomSource;
 
+    private int denyStatus = HttpServletResponse.SC_FORBIDDEN;
+
     private final Set<String> entryPoints = new HashSet<String>();
     
     private int nonceCacheSize = 5;
@@ -66,6 +69,24 @@ public class CsrfPreventionFilter extends FilterBase {
     }
 
     /**
+     * Return response status code that is used to reject denied request.
+     */
+    public int getDenyStatus() {
+        return denyStatus;
+    }
+
+    /**
+     * Set response status code that is used to reject denied request. If none
+     * set, the default value of 403 will be used.
+     *
+     * @param denyStatus
+     *            HTTP status code
+     */
+    public void setDenyStatus(int denyStatus) {
+        this.denyStatus = denyStatus;
+    }
+
+    /**
      * Entry points are URLs that will not be tested for the presence of a valid
      * nonce. They are used to provide a way to navigate back to a protected
      * application after navigating away from it. Entry points will be limited
@@ -153,24 +174,30 @@ public class CsrfPreventionFilter extends FilterBase {
                 }
             }
 
+            HttpSession session = req.getSession(false);
+
             @SuppressWarnings("unchecked")
-            LruCache<String> nonceCache =
-                (LruCache<String>) req.getSession(true).getAttribute(
-                    Constants.CSRF_NONCE_SESSION_ATTR_NAME);
-            
+            LruCache<String> nonceCache = (session == null) ? null
+                    : (LruCache<String>) session.getAttribute(
+                            Constants.CSRF_NONCE_SESSION_ATTR_NAME);
+
             if (!skipNonceCheck) {
                 String previousNonce =
                     req.getParameter(Constants.CSRF_NONCE_REQUEST_PARAM);
 
-                if (nonceCache != null && !nonceCache.contains(previousNonce)) {
-                    res.sendError(HttpServletResponse.SC_FORBIDDEN);
+                if (nonceCache == null || previousNonce == null ||
+                        !nonceCache.contains(previousNonce)) {
+                    res.sendError(denyStatus);
                     return;
                 }
             }
             
             if (nonceCache == null) {
                 nonceCache = new LruCache<String>(nonceCacheSize);
-                req.getSession().setAttribute(
+                if (session == null) {
+                    session = req.getSession(true);
+                }
+                session.setAttribute(
                         Constants.CSRF_NONCE_SESSION_ATTR_NAME, nonceCache);
             }
             
diff --git a/java/org/apache/catalina/ha/context/ReplicatedContext.java b/java/org/apache/catalina/ha/context/ReplicatedContext.java
index a126e56..bea1cc0 100644
--- a/java/org/apache/catalina/ha/context/ReplicatedContext.java
+++ b/java/org/apache/catalina/ha/context/ReplicatedContext.java
@@ -168,10 +168,12 @@ public class ReplicatedContext extends StandardContext implements MapOwner {
         
         @Override
         public Object getAttribute(String name) {
-            if (tomcatAttributes.containsKey(name) )
-                return tomcatAttributes.get(name);
-            else 
+            Object obj = tomcatAttributes.get(name);
+            if (obj == null) {
                 return super.getAttribute(name);
+            } else {
+                return obj;
+            }
         }
         
         @SuppressWarnings("unchecked")
diff --git a/java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml b/java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml
index 76a1746..eb360b2 100644
--- a/java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml
@@ -19,10 +19,10 @@
   <mbean
     name="FarmWarDeployer"
     className="org.apache.catalina.mbeans.ClassNameMBean"
-    description="Farm Deployer - Broken"
+    description="Farm Deployer"
     domain="Catalina"
     group="Cluster"
-    type="org.apache.catalina.ha.deploy.FarmWarDeployer"/>
+    type="org.apache.catalina.ha.deploy.FarmWarDeployer">
     <attribute
       name="deployDir"
       description="Deployment directory."
@@ -39,4 +39,5 @@
       name="watchEnabled"
       description="Is watching enabled?"
       type="boolean"/>
+  </mbean>
 </mbeans-descriptors>
diff --git a/java/org/apache/catalina/ha/jmx/ClusterJmxHelper.java b/java/org/apache/catalina/ha/jmx/ClusterJmxHelper.java
index 3b0a173..cce8e4a 100644
--- a/java/org/apache/catalina/ha/jmx/ClusterJmxHelper.java
+++ b/java/org/apache/catalina/ha/jmx/ClusterJmxHelper.java
@@ -23,9 +23,7 @@ import javax.management.ObjectName;
 
 import org.apache.catalina.core.StandardEngine;
 import org.apache.catalina.core.StandardHost;
-import org.apache.catalina.ha.authenticator.ClusterSingleSignOn;
 import org.apache.catalina.ha.deploy.FarmWarDeployer;
-import org.apache.catalina.ha.session.DeltaManager;
 import org.apache.catalina.ha.tcp.SimpleTcpCluster;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -34,7 +32,11 @@ import org.apache.tomcat.util.modeler.Registry;
 /**
  * 
  * @author Filip Hanik
+ *
+ * @deprecated  Unused - registration now happens via
+ *              {@link org.apache.catalina.util.LifecycleMBeanBase}
  */
+ at Deprecated
 public class ClusterJmxHelper {
     
     protected static Registry registry = Registry.getRegistry(null,null);
@@ -83,9 +85,7 @@ public class ClusterJmxHelper {
     
     protected static void initDefaultCluster() {
         initMetaData(SimpleTcpCluster.class);
-        initMetaData(DeltaManager.class);
         initMetaData(FarmWarDeployer.class); //not functional yet
-        initMetaData(ClusterSingleSignOn.class); //not functional yet
     }
     
     public static boolean registerDefaultCluster(SimpleTcpCluster cluster)  {
diff --git a/java/org/apache/catalina/ha/session/mbeans-descriptors.xml b/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
index 0f4359d..ef91fdb 100644
--- a/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
@@ -629,10 +629,10 @@
       impact="ACTION"
       returnType="java.lang.String"/>
     <operation
-      name="listSessionIdsFull"
-      description="Return the list of active session ids"
+      name="getSessionIdsFull"
+      description="Returns the list of all sessions IDS (primary, backup and proxy)."
       impact="ACTION"
-      returnType="java.lang.String"/>
+      returnType="java.util.Set"/>
     <operation
       name="processExpires"
       description="Invalidate all sessions that have expired.s"
diff --git a/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java b/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java
index 923ea6c..154096a 100644
--- a/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java
+++ b/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java
@@ -24,6 +24,9 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.management.ObjectName;
 
 import org.apache.catalina.Container;
 import org.apache.catalina.Context;
@@ -40,12 +43,13 @@ import org.apache.catalina.ha.ClusterListener;
 import org.apache.catalina.ha.ClusterManager;
 import org.apache.catalina.ha.ClusterMessage;
 import org.apache.catalina.ha.ClusterValve;
-import org.apache.catalina.ha.jmx.ClusterJmxHelper;
 import org.apache.catalina.ha.session.ClusterSessionListener;
 import org.apache.catalina.ha.session.DeltaManager;
 import org.apache.catalina.ha.session.JvmRouteBinderValve;
 import org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener;
+import org.apache.catalina.ha.session.SessionMessage;
 import org.apache.catalina.ha.util.IDynamicProperty;
+import org.apache.catalina.mbeans.MBeanUtils;
 import org.apache.catalina.tribes.Channel;
 import org.apache.catalina.tribes.ChannelListener;
 import org.apache.catalina.tribes.Member;
@@ -53,7 +57,7 @@ import org.apache.catalina.tribes.MembershipListener;
 import org.apache.catalina.tribes.group.GroupChannel;
 import org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor;
 import org.apache.catalina.tribes.group.interceptors.TcpFailureDetector;
-import org.apache.catalina.util.LifecycleBase;
+import org.apache.catalina.util.LifecycleMBeanBase;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.IntrospectionUtils;
@@ -64,16 +68,15 @@ import org.apache.tomcat.util.res.StringManager;
  * setting up a cluster and provides callers with a valid multicast
  * receiver/sender.
  * 
- * FIXME remove install/remove/start/stop context dummys
  * FIXME wrote testcases 
  * 
  * @author Filip Hanik
  * @author Remy Maucherat
  * @author Peter Rossbach
- * @version $Id: SimpleTcpCluster.java 1069836 2011-02-11 15:29:34Z markt $
+ * @version $Id: SimpleTcpCluster.java 1392624 2012-10-01 21:26:20Z markt $
  */
-public class SimpleTcpCluster extends LifecycleBase
-    implements CatalinaCluster, LifecycleListener, IDynamicProperty,
+public class SimpleTcpCluster extends LifecycleMBeanBase
+        implements CatalinaCluster, LifecycleListener, IDynamicProperty,
                MembershipListener, ChannelListener{
 
     public static final Log log = LogFactory.getLog(SimpleTcpCluster.class);
@@ -153,6 +156,7 @@ public class SimpleTcpCluster extends LifecycleBase
     private List<Valve> valves = new ArrayList<Valve>();
 
     private org.apache.catalina.ha.ClusterDeployer clusterDeployer;
+    private ObjectName onameClusterDeployer;
 
     /**
      * Listeners of messages
@@ -173,6 +177,9 @@ public class SimpleTcpCluster extends LifecycleBase
     
     private int channelStartOptions = Channel.DEFAULT;
 
+    private Map<Member,ObjectName> memberOnameMap =
+            new ConcurrentHashMap<Member,ObjectName>();
+
     // ------------------------------------------------------------- Properties
 
     public SimpleTcpCluster() {
@@ -625,17 +632,26 @@ public class SimpleTcpCluster extends LifecycleBase
             log.trace(sm.getString("SimpleTcpCluster.event.log", lifecycleEvent.getType(), lifecycleEvent.getData()));
     }
 
+
     // ------------------------------------------------------ public
 
+    @SuppressWarnings("deprecation")
     @Override
-    protected void initInternal() {
-        // NOOP
+    protected void initInternal() throws LifecycleException {
+        super.initInternal();
+        if (clusterDeployer != null) {
+            StringBuilder name = new StringBuilder("type=Cluster");
+            Container container = getContainer();
+            name.append(MBeanUtils.getContainerKeyProperties(container));
+            name.append(",component=Deployer");
+            onameClusterDeployer = register(clusterDeployer, name.toString());
+        }
     }
     
     
     /**
      * Start Cluster and implement the requirements
-     * of {@link LifecycleBase#startInternal()}.
+     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
      *
      * @exception LifecycleException if this component detects a fatal error
      *  that prevents this component from being used
@@ -652,9 +668,7 @@ public class SimpleTcpCluster extends LifecycleBase
             channel.addChannelListener(this);
             channel.start(channelStartOptions);
             if (clusterDeployer != null) clusterDeployer.start();
-            //register JMX objects
-            ClusterJmxHelper.registerDefaultCluster(this);
-            // Notify our interested LifecycleListeners
+            registerMember(channel.getLocalMember(false));
         } catch (Exception x) {
             log.error("Unable to start cluster.", x);
             throw new LifecycleException(x);
@@ -726,7 +740,7 @@ public class SimpleTcpCluster extends LifecycleBase
     
     /**
      * Stop Cluster and implement the requirements
-     * of {@link LifecycleBase#startInternal()}.
+     * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
      *
      * @exception LifecycleException if this component detects a fatal error
      *  that prevents this component from being used
@@ -736,6 +750,7 @@ public class SimpleTcpCluster extends LifecycleBase
 
         setState(LifecycleState.STOPPING);
 
+        unregisterMember(channel.getLocalMember(false));
         if (clusterDeployer != null) clusterDeployer.stop();
         this.managers.clear();
         try {
@@ -744,9 +759,6 @@ public class SimpleTcpCluster extends LifecycleBase
             channel.removeChannelListener(this);
             channel.removeMembershipListener(this);
             this.unregisterClusterValve();
-            //unregister JMX objects
-            ClusterJmxHelper.unregisterDefaultCluster(this);
-
         } catch (Exception x) {
             log.error("Unable to stop cluster valve.", x);
         }
@@ -754,8 +766,12 @@ public class SimpleTcpCluster extends LifecycleBase
 
     
     @Override
-    protected void destroyInternal() {
-        // NOOP
+    protected void destroyInternal() throws LifecycleException {
+        if (onameClusterDeployer != null) {
+            unregister(onameClusterDeployer);
+            onameClusterDeployer = null;
+        }
+        super.destroyInternal();
     }
 
     
@@ -799,15 +815,20 @@ public class SimpleTcpCluster extends LifecycleBase
     public void send(ClusterMessage msg, Member dest) {
         try {
             msg.setAddress(getLocalMember());
+            int sendOptions = channelSendOptions;
+            if (msg instanceof SessionMessage
+                    && ((SessionMessage)msg).getEventType() == SessionMessage.EVT_ALL_SESSION_DATA) {
+                sendOptions = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK|Channel.SEND_OPTIONS_USE_ACK;
+            }
             if (dest != null) {
                 if (!getLocalMember().equals(dest)) {
-                    channel.send(new Member[] {dest}, msg,channelSendOptions);
+                    channel.send(new Member[] {dest}, msg, sendOptions);
                 } else
                     log.error("Unable to send message to local member " + msg);
             } else {
                 Member[] destmembers = channel.getMembers();
                 if (destmembers.length>0)
-                    channel.send(destmembers,msg,channelSendOptions);
+                    channel.send(destmembers,msg, sendOptions);
                 else if (log.isDebugEnabled()) 
                     log.debug("No members in cluster, ignoring message:"+msg);
             }
@@ -828,6 +849,9 @@ public class SimpleTcpCluster extends LifecycleBase
             if (log.isInfoEnabled()) log.info("Replication member added:" + member);
             // Notify our interested LifecycleListeners
             fireLifecycleEvent(BEFORE_MEMBERREGISTER_EVENT, member);
+
+            registerMember(member);
+
             // Notify our interested LifecycleListeners
             fireLifecycleEvent(AFTER_MEMBERREGISTER_EVENT, member);
         } catch (Exception x) {
@@ -848,6 +872,9 @@ public class SimpleTcpCluster extends LifecycleBase
             if (log.isInfoEnabled()) log.info("Received member disappeared:" + member);
             // Notify our interested LifecycleListeners
             fireLifecycleEvent(BEFORE_MEMBERUNREGISTER_EVENT, member);
+
+            unregisterMember(member);
+
             // Notify our interested LifecycleListeners
             fireLifecycleEvent(AFTER_MEMBERUNREGISTER_EVENT, member);
         } catch (Exception x) {
@@ -946,4 +973,52 @@ public class SimpleTcpCluster extends LifecycleBase
     public void setChannelStartOptions(int channelStartOptions) {
         this.channelStartOptions = channelStartOptions;
     }
+
+
+    // --------------------------------------------------------------------- JMX
+
+    @SuppressWarnings("deprecation")
+    @Override
+    protected String getDomainInternal() {
+        Container container = getContainer();
+        if (container == null) {
+            return null;
+        }
+        return MBeanUtils.getDomain(container);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    protected String getObjectNameKeyProperties() {
+        StringBuilder name = new StringBuilder("type=Cluster");
+
+        Container container = getContainer();
+        if (container != null) {
+            name.append(MBeanUtils.getContainerKeyProperties(container));
+        }
+
+        return name.toString();
+    }
+
+    @SuppressWarnings("deprecation")
+    private void registerMember(Member member) {
+        // JMX registration
+        StringBuilder name = new StringBuilder("type=Cluster");
+        Container container = getContainer();
+        if (container != null) {
+            name.append(MBeanUtils.getContainerKeyProperties(container));
+        }
+        name.append(",component=Member,name=");
+        name.append(ObjectName.quote(member.getName()));
+
+        ObjectName oname = register(member, name.toString());
+        memberOnameMap.put(member, oname);
+    }
+
+    private void unregisterMember(Member member) {
+        ObjectName oname = memberOnameMap.remove(member);
+        if (oname != null) {
+            unregister(oname);
+        }
+    }
 }
diff --git a/java/org/apache/catalina/loader/VirtualWebappLoader.java b/java/org/apache/catalina/loader/VirtualWebappLoader.java
index 39a7ce6..5092c1f 100644
--- a/java/org/apache/catalina/loader/VirtualWebappLoader.java
+++ b/java/org/apache/catalina/loader/VirtualWebappLoader.java
@@ -47,7 +47,7 @@ import org.apache.catalina.LifecycleException;
  *
  *
  * @author Fabrizio Giustina
- * @version $Id: VirtualWebappLoader.java 1292342 2012-02-22 15:24:25Z kkolinko $
+ * @version $Id: VirtualWebappLoader.java 1401477 2012-10-23 21:04:54Z rjung $
  */
 public class VirtualWebappLoader extends WebappLoader {
 
@@ -57,7 +57,7 @@ public class VirtualWebappLoader extends WebappLoader {
     /**
      * <code>;</code> separated list of additional path elements.
      */
-    private String virtualClasspath;
+    private String virtualClasspath = "";
 
     /**
      * Construct a new WebappLoader with no defined parent class loader (so that
diff --git a/java/org/apache/catalina/loader/WebappClassLoader.java b/java/org/apache/catalina/loader/WebappClassLoader.java
index b182ce3..f6a065e 100644
--- a/java/org/apache/catalina/loader/WebappClassLoader.java
+++ b/java/org/apache/catalina/loader/WebappClassLoader.java
@@ -119,7 +119,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Craig R. McClanahan
- * @version $Id: WebappClassLoader.java 1348120 2012-06-08 15:39:09Z kkolinko $
+ * @version $Id: WebappClassLoader.java 1361987 2012-07-16 12:20:10Z rjung $
  */
 public class WebappClassLoader
     extends URLClassLoader
@@ -240,6 +240,9 @@ public class WebappClassLoader
     /**
      * Construct a new ClassLoader with no defined repositories and the given
      * parent ClassLoader.
+     * <p>
+     * Method is used via reflection -
+     * see {@link WebappLoader#createClassLoader()}
      *
      * @param parent Our parent class loader
      */
@@ -1775,11 +1778,11 @@ public class WebappClassLoader
                 off = externalsLength;
             }
             for (i = 0; i < filesLength; i++) {
-                urls[off + i] = getURL(files[i], true);
+                urls[off + i] = getURI(files[i]);
             }
             off += filesLength;
             for (i = 0; i < jarFilesLength; i++) {
-                urls[off + i] = getURL(jarRealFiles[i], true);
+                urls[off + i] = getURI(jarRealFiles[i]);
             }
             off += jarFilesLength;
             if (!searchExternalFirst) {
@@ -2928,7 +2931,7 @@ public class WebappClassLoader
         ResourceEntry entry = new ResourceEntry();
         try {
             entry.source = getURI(new File(file, path));
-            entry.codeBase = getURL(new File(file, path), false);
+            entry.codeBase = entry.source;
         } catch (MalformedURLException e) {
             return null;
         }
@@ -3062,8 +3065,8 @@ public class WebappClassLoader
 
                         entry = new ResourceEntry();
                         try {
-                            entry.codeBase = getURL(jarRealFiles[i], false);
-                            String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+                            entry.codeBase = getURI(jarRealFiles[i]);
+                            String jarFakeUrl = entry.codeBase.toString();
                             jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
                             entry.source = new URL(jarFakeUrl);
                             entry.lastModified = jarRealFiles[i].lastModified();
@@ -3449,7 +3452,9 @@ public class WebappClassLoader
 
     /**
      * Get URL.
+     * @deprecated Use {@link #getURI(File)} instead
      */
+    @Deprecated
     protected URL getURL(File file, boolean encoded)
         throws MalformedURLException {
 
@@ -3468,7 +3473,7 @@ public class WebappClassLoader
 
 
     /**
-     * Get URL.
+     * Get the URI for the given file.
      */
     protected URL getURI(File file)
         throws MalformedURLException {
diff --git a/java/org/apache/catalina/manager/HTMLManagerServlet.java b/java/org/apache/catalina/manager/HTMLManagerServlet.java
index 1b07ca8..22bbc04 100644
--- a/java/org/apache/catalina/manager/HTMLManagerServlet.java
+++ b/java/org/apache/catalina/manager/HTMLManagerServlet.java
@@ -77,7 +77,7 @@ import org.apache.tomcat.util.res.StringManager;
 * @author Bip Thelin
 * @author Malcolm Edgar
 * @author Glenn L. Nielsen
-* @version $Id: HTMLManagerServlet.java 1349885 2012-06-13 14:43:14Z markt $
+* @version $Id: HTMLManagerServlet.java 1390886 2012-09-27 08:24:49Z markt $
 * @see ManagerServlet
 */
 
@@ -492,7 +492,7 @@ public final class HTMLManagerServlet extends ManagerServlet {
                 }
                 
                 args = new Object[7];
-                args[0] = "<a href=\"" + URL_ENCODER.encode(displayPath)
+                args[0] = "<a href=\"" + URL_ENCODER.encode(contextPath + "/")
                         + "\">" + RequestUtil.filter(displayPath) + "</a>";
                 if ("".equals(ctxt.getWebappVersion())) {
                     args[1] = noVersion;
@@ -504,7 +504,7 @@ public final class HTMLManagerServlet extends ManagerServlet {
                 } else {
                     args[2] = RequestUtil.filter(ctxt.getDisplayName());
                 }
-                args[3] = Boolean.valueOf(ctxt.getAvailable());
+                args[3] = Boolean.valueOf(ctxt.getState().isAvailable());
                 args[4] = RequestUtil.filter(response.encodeURL(request.getContextPath() +
                      "/html/sessions?" + pathVersion));
                 Manager manager = ctxt.getManager(); 
@@ -553,13 +553,13 @@ public final class HTMLManagerServlet extends ManagerServlet {
                 if (ctxt.getName().equals(this.context.getName())) {
                     writer.print(MessageFormat.format(
                         MANAGER_APP_ROW_BUTTON_SECTION, args));
-                } else if (ctxt.getAvailable() && isDeployed) {
+                } else if (ctxt.getState().isAvailable() && isDeployed) {
                     writer.print(MessageFormat.format(
                         STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args));
-                } else if (ctxt.getAvailable() && !isDeployed) {
+                } else if (ctxt.getState().isAvailable() && !isDeployed) {
                     writer.print(MessageFormat.format(
                         STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args));
-                } else if (!ctxt.getAvailable() && isDeployed) {
+                } else if (!ctxt.getState().isAvailable() && isDeployed) {
                     writer.print(MessageFormat.format(
                         STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args));
                 } else {
diff --git a/java/org/apache/catalina/manager/JMXProxyServlet.java b/java/org/apache/catalina/manager/JMXProxyServlet.java
index e217598..5d277bf 100644
--- a/java/org/apache/catalina/manager/JMXProxyServlet.java
+++ b/java/org/apache/catalina/manager/JMXProxyServlet.java
@@ -21,10 +21,13 @@ import java.io.PrintWriter;
 import java.util.Set;
 
 import javax.management.Attribute;
+import javax.management.MBeanException;
 import javax.management.MBeanOperationInfo;
 import javax.management.MBeanParameterInfo;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.ReflectionException;
 import javax.management.openmbean.CompositeData;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -44,6 +47,10 @@ public class JMXProxyServlet extends HttpServlet  {
     
     private static final long serialVersionUID = 1L;
 
+    // Constant for "no parameters" when invoking a JMX operation
+    // without any parameters.
+    private static final String[] NO_PARAMETERS = new String[0];
+
     // ----------------------------------------------------- Instance Variables
     /**
      * MBean server.
@@ -77,7 +84,6 @@ public class JMXProxyServlet extends HttpServlet  {
                       HttpServletResponse response)
         throws IOException, ServletException
     {
-
         response.setContentType("text/plain");
 
         PrintWriter writer = response.getWriter();
@@ -104,14 +110,8 @@ public class JMXProxyServlet extends HttpServlet  {
         qry = request.getParameter("invoke");
         if(qry != null) {
             String opName=request.getParameter("op");
-            String ps = request.getParameter("ps");
-            String[] valuesStr;
-            if (ps == null) {
-                valuesStr = new String[0];
-            } else {
-                valuesStr = ps.split(",");
-            }
-            invokeOperation( writer, qry, opName,valuesStr );
+            String[] params = getInvokeParameters(request.getParameter("ps"));
+            invokeOperation(writer, qry, opName, params);
             return;
         }
         qry=request.getParameter("qry");
@@ -120,7 +120,6 @@ public class JMXProxyServlet extends HttpServlet  {
         }
 
         listBeans( writer, qry );
-
     }
 
     public void getAttribute(PrintWriter writer, String onameStr, String att, String key) {
@@ -162,10 +161,7 @@ public class JMXProxyServlet extends HttpServlet  {
                               String onameStr, String att, String val )
     {
         try {
-            ObjectName oname=new ObjectName( onameStr );
-            String type=registry.getType(oname, att);
-            Object valueObj=registry.convertValue(type, val );
-            mBeanServer.setAttribute( oname, new Attribute(att, valueObj));
+            setAttributeInternal(onameStr, att, val);
             writer.println("OK - Attribute set");
         } catch( Exception ex ) {
             writer.println("Error - " + ex.toString());
@@ -205,18 +201,7 @@ public class JMXProxyServlet extends HttpServlet  {
     private void invokeOperation(PrintWriter writer, String onameStr, String op,
             String[] valuesStr) {
         try {
-            ObjectName oname=new ObjectName( onameStr );
-            MBeanOperationInfo methodInfo = registry.getMethodInfo(oname,op);
-            MBeanParameterInfo[] signature = methodInfo.getSignature();
-            String[] signatureTypes = new String[signature.length];
-            Object[] values = new Object[signature.length];
-            for (int i = 0; i < signature.length; i++) {
-               MBeanParameterInfo pi = signature[i];
-               signatureTypes[i] = pi.getType();
-               values[i] = registry.convertValue(pi.getType(), valuesStr[i] );
-           }
-
-            Object retVal = mBeanServer.invoke(oname,op,values,signatureTypes);
+            Object retVal = invokeOperationInternal(onameStr, op, valuesStr);
             if (retVal != null) {
                 writer.println("OK - Operation " + op + " returned:");
                 output("", writer, retVal);
@@ -229,6 +214,62 @@ public class JMXProxyServlet extends HttpServlet  {
         }
     }
 
+
+    /**
+     * Parses parameter values from a parameter string.
+     * @param paramString The string containing comma-separated
+     *                    operation-invocation parameters, or
+     *                    <code>null</code> if there are no parameters.
+     * @return An array of String parameters (empty array if
+     *         <code>paramString</code> was <code>null</code>).
+     */
+    private String[] getInvokeParameters(String paramString) {
+        if (paramString == null)
+            return NO_PARAMETERS;
+        else
+            return paramString.split(",");
+    }
+
+    /**
+     * Sets an MBean attribute's value.
+     */
+    private void setAttributeInternal(String onameStr,
+                                      String attributeName,
+                                      String value)
+        throws OperationsException, MBeanException, ReflectionException {
+        ObjectName oname=new ObjectName( onameStr );
+        String type=registry.getType(oname, attributeName);
+        Object valueObj=registry.convertValue(type, value );
+        mBeanServer.setAttribute( oname, new Attribute(attributeName, valueObj));
+    }
+
+    /**
+     * Invokes an operation on an MBean.
+     * @param onameStr The name of the MBean.
+     * @param operation The name of the operation to invoke.
+     * @param parameters An array of Strings containing the parameters to the
+     *                   operation. They will be converted to the appropriate
+     *                   types to call the reuested operation.
+     * @return The value returned by the requested operation.
+     */
+    private Object invokeOperationInternal(String onameStr,
+                                           String operation,
+                                           String[] parameters)
+        throws OperationsException, MBeanException, ReflectionException {
+        ObjectName oname=new ObjectName( onameStr );
+        MBeanOperationInfo methodInfo = registry.getMethodInfo(oname,operation);
+        MBeanParameterInfo[] signature = methodInfo.getSignature();
+        String[] signatureTypes = new String[signature.length];
+        Object[] values = new Object[signature.length];
+        for (int i = 0; i < signature.length; i++) {
+           MBeanParameterInfo pi = signature[i];
+           signatureTypes[i] = pi.getType();
+           values[i] = registry.convertValue(pi.getType(), parameters[i] );
+         }
+
+        return mBeanServer.invoke(oname,operation,values,signatureTypes);
+    }
+
     private void output(String indent, PrintWriter writer, Object result) {
         if (result instanceof Object[]) {
             for (Object obj : (Object[]) result) {
diff --git a/java/org/apache/catalina/manager/ManagerServlet.java b/java/org/apache/catalina/manager/ManagerServlet.java
index 9822794..a511d8c 100644
--- a/java/org/apache/catalina/manager/ManagerServlet.java
+++ b/java/org/apache/catalina/manager/ManagerServlet.java
@@ -148,7 +148,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: ManagerServlet.java 1162172 2011-08-26 17:12:33Z markt $
+ * @version $Id: ManagerServlet.java 1390886 2012-09-27 08:24:49Z markt $
  */
 
 public class ManagerServlet extends HttpServlet implements ContainerServlet {
@@ -193,7 +193,9 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
 
     /**
      * Path used to store context descriptors.
+     * @deprecated  Unused
      */
+    @Deprecated
     protected File contextDescriptors = null;
 
 
@@ -205,10 +207,12 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
     
     /**
      * The host appBase.
+     * @deprecated  Unused
      */
+    @Deprecated
     protected File appBase = null;
-    
-    
+
+
     /**
      * MBean server.
      */
@@ -859,10 +863,11 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
                 }
             }
             context = (Context) host.findChild(name);
-            if (context != null && context.getConfigured() && context.getAvailable()) {
+            if (context != null && context.getConfigured() &&
+                    context.getState().isAvailable()) {
                 writer.println(smClient.getString(
                         "managerServlet.deployed", displayPath));
-            } else if (context!=null && !context.getAvailable()) {
+            } else if (context!=null && !context.getState().isAvailable()) {
                 writer.println(smClient.getString(
                         "managerServlet.deployedButNotStarted", displayPath));
             } else {
@@ -900,7 +905,7 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
                 String displayPath = context.getPath();
                 if( displayPath.equals("") )
                     displayPath = "/";
-                if (context.getAvailable()) {
+                if (context.getState().isAvailable()) {
                     writer.println(smClient.getString("managerServlet.listitem",
                             displayPath,
                             "running",
@@ -1191,7 +1196,11 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
      *
      * @param writer Writer to render to
      * @param cn Name of the application to list session information for
+     *
+     * @deprecated  Use {@link #sessions(PrintWriter, ContextName, int,
+     *              StringManager)}
      */
+    @Deprecated
     protected void sessions(PrintWriter writer, ContextName cn,
             StringManager smClient) {
         sessions(writer, cn, -1, smClient);
@@ -1245,7 +1254,7 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
                 return;
             }
             context.start();
-            if (context.getAvailable())
+            if (context.getState().isAvailable())
                 writer.println(smClient.getString("managerServlet.started",
                         displayPath));
             else
diff --git a/java/org/apache/catalina/manager/StatusTransformer.java b/java/org/apache/catalina/manager/StatusTransformer.java
index eac7721..7d98903 100644
--- a/java/org/apache/catalina/manager/StatusTransformer.java
+++ b/java/org/apache/catalina/manager/StatusTransformer.java
@@ -19,12 +19,17 @@
 package org.apache.catalina.manager;
 
 import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.MemoryUsage;
 import java.lang.reflect.Method;
 import java.text.MessageFormat;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.Vector;
 
 import javax.management.MBeanServer;
@@ -41,7 +46,7 @@ import org.apache.tomcat.util.ExceptionUtils;
  * use XSLT, that is unnecessarily complex.
  *
  * @author Peter Lin
- * @version $Id: StatusTransformer.java 1348992 2012-06-11 20:20:23Z markt $
+ * @version $Id: StatusTransformer.java 1409014 2012-11-13 22:58:01Z kkolinko $
  */
 
 public class StatusTransformer {
@@ -200,6 +205,13 @@ public class StatusTransformer {
     public static void writeVMState(PrintWriter writer, int mode)
         throws Exception {
 
+        SortedMap<String, MemoryPoolMXBean> memoryPoolMBeans =
+                new TreeMap<String, MemoryPoolMXBean>();
+        for (MemoryPoolMXBean mbean: ManagementFactory.getMemoryPoolMXBeans()) {
+            String sortKey = mbean.getType() + ":" + mbean.getName();
+            memoryPoolMBeans.put(sortKey, mbean);
+        }
+
         if (mode == 0){
             writer.print("<h1>JVM</h1>");
 
@@ -214,6 +226,29 @@ public class StatusTransformer {
             writer.print(formatSize(
                     Long.valueOf(Runtime.getRuntime().maxMemory()), true));
             writer.print("</p>");
+
+            writer.write("<table border=\"0\"><thead><tr><th>Memory Pool</th><th>Type</th><th>Initial</th><th>Total</th><th>Maximum</th><th>Used</th></tr></thead><tbody>");
+            for (MemoryPoolMXBean memoryPoolMBean : memoryPoolMBeans.values()) {
+                MemoryUsage usage = memoryPoolMBean.getUsage();
+                writer.write("<tr><td>");
+                writer.print(memoryPoolMBean.getName());
+                writer.write("</td><td>");
+                writer.print(memoryPoolMBean.getType());
+                writer.write("</td><td>");
+                writer.print(formatSize(Long.valueOf(usage.getInit()), true));
+                writer.write("</td><td>");
+                writer.print(formatSize(Long.valueOf(usage.getCommitted()), true));
+                writer.write("</td><td>");
+                writer.print(formatSize(Long.valueOf(usage.getMax()), true));
+                writer.write("</td><td>");
+                writer.print(formatSize(Long.valueOf(usage.getUsed()), true));
+                if (usage.getMax() > 0) {
+                    writer.write(" ("
+                            + (usage.getUsed() * 100 / usage.getMax()) + "%)");
+                }
+                writer.write("</td></tr>");
+            }
+            writer.write("</tbody></table>");
         } else if (mode == 1){
             writer.write("<jvm>");
 
@@ -222,6 +257,17 @@ public class StatusTransformer {
             writer.write(" total='" + Runtime.getRuntime().totalMemory() + "'");
             writer.write(" max='" + Runtime.getRuntime().maxMemory() + "'/>");
 
+            for (MemoryPoolMXBean memoryPoolMBean : memoryPoolMBeans.values()) {
+                MemoryUsage usage = memoryPoolMBean.getUsage();
+                writer.write("<memorypool");
+                writer.write(" name='" + memoryPoolMBean.getName() + "'");
+                writer.write(" type='" + memoryPoolMBean.getType() + "'");
+                writer.write(" usageInit='" + usage.getInit() + "'");
+                writer.write(" usageCommitted='" + usage.getCommitted() + "'");
+                writer.write(" usageMax='" + usage.getMax() + "'");
+                writer.write(" usageUsed='" + usage.getInit() + "'/>");
+            }
+
             writer.write("</jvm>");
         }
 
diff --git a/java/org/apache/catalina/mbeans/MBeanFactory.java b/java/org/apache/catalina/mbeans/MBeanFactory.java
index 5bb8e0f..6d729bb 100644
--- a/java/org/apache/catalina/mbeans/MBeanFactory.java
+++ b/java/org/apache/catalina/mbeans/MBeanFactory.java
@@ -57,7 +57,7 @@ import org.apache.catalina.valves.ValveBase;
  * <code>org.apache.catalina.core.StandardServer</code> component.</p>
  *
  * @author Amy Roh
- * @version $Id: MBeanFactory.java 1240334 2012-02-03 20:17:37Z markt $
+ * @version $Id: MBeanFactory.java 1361764 2012-07-15 19:14:11Z markt $
  */
 
 public class MBeanFactory {
@@ -111,7 +111,10 @@ public class MBeanFactory {
      * Return the managed bean definition for the specified bean type
      *
      * @param type MBean type
+     *
+     * @deprecated  Unused
      */
+    @Deprecated
     public String findObjectName(String type) {
 
         if (type.equals("org.apache.catalina.core.StandardContext")) {
diff --git a/java/org/apache/catalina/realm/GenericPrincipal.java b/java/org/apache/catalina/realm/GenericPrincipal.java
index bafd141..2bad6fb 100644
--- a/java/org/apache/catalina/realm/GenericPrincipal.java
+++ b/java/org/apache/catalina/realm/GenericPrincipal.java
@@ -33,7 +33,7 @@ import org.ietf.jgss.GSSCredential;
  * is available for use by <code>Realm</code> implementations.
  *
  * @author Craig R. McClanahan
- * @version $Id: GenericPrincipal.java 1186071 2011-10-19 10:21:28Z markt $
+ * @version $Id: GenericPrincipal.java 1361770 2012-07-15 19:38:51Z markt $
  */
 
 public class GenericPrincipal implements Principal {
@@ -48,7 +48,10 @@ public class GenericPrincipal implements Principal {
      *
      * @param name The username of the user represented by this Principal
      * @param password Credentials used to authenticate this user
+     *
+     * @deprecated  Unused
      */
+    @Deprecated
     public GenericPrincipal(String name, String password) {
 
         this(name, password, null);
diff --git a/java/org/apache/catalina/realm/JAASRealm.java b/java/org/apache/catalina/realm/JAASRealm.java
index adc4da8..a486a53 100644
--- a/java/org/apache/catalina/realm/JAASRealm.java
+++ b/java/org/apache/catalina/realm/JAASRealm.java
@@ -122,7 +122,7 @@ org.foobar.auth.DatabaseLoginModule REQUIRED
 *
 * @author Craig R. McClanahan
 * @author Yoav Shapira
- * @version $Id: JAASRealm.java 1189224 2011-10-26 14:02:40Z kkolinko $
+ * @version $Id: JAASRealm.java 1361770 2012-07-15 19:38:51Z markt $
  */
 
 public class JAASRealm
@@ -178,9 +178,7 @@ public class JAASRealm
     
     /**
      * setter for the <code>appName</code> member variable
-     * @deprecated JAAS should use the <code>Engine</code> (domain) name and webpp/host overrides
      */
-    @Deprecated
     public void setAppName(String name) {
         appName = name;
     }
diff --git a/java/org/apache/catalina/realm/JDBCRealm.java b/java/org/apache/catalina/realm/JDBCRealm.java
index cea27df..40d43c2 100644
--- a/java/org/apache/catalina/realm/JDBCRealm.java
+++ b/java/org/apache/catalina/realm/JDBCRealm.java
@@ -47,7 +47,7 @@ import org.apache.tomcat.util.ExceptionUtils;
 * @author Craig R. McClanahan
 * @author Carson McDonald
 * @author Ignacio Ortega
-* @version $Id: JDBCRealm.java 1348499 2012-06-09 20:37:14Z markt $
+* @version $Id: JDBCRealm.java 1361770 2012-07-15 19:38:51Z markt $
 */
 
 public class JDBCRealm
@@ -728,7 +728,10 @@ public class JDBCRealm
      * Release our use of this connection so that it can be recycled.
      *
      * @param dbConnection The connection to be released
+     *
+     * @deprecated  Unused
      */
+    @Deprecated
     protected void release(Connection dbConnection) {
 
         // NO-OP since we are not pooling anything
diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index 541063f..3ca725f 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -126,8 +126,10 @@ import org.ietf.jgss.GSSCredential;
  *         property.</li>
  *     <li>The <code>roleSearch</code> pattern optionally includes pattern
  *         replacements "{0}" for the distinguished name, and/or "{1}" for
- *         the username, of the authenticated user for which roles will be
- *         retrieved.</li>
+ *         the username, and/or "{2}" the value of an attribute from the
+ *         user's directory entry (the attribute is specified by the
+ *         <code>userRoleAttribute</code> property), of the authenticated user
+ *         for which roles will be retrieved.</li>
  *     <li>The <code>roleBase</code> property can be set to the element that
  *         is the base of the search for matching roles.  If not specified,
  *         the entire context will be searched.</li>
@@ -172,7 +174,7 @@ import org.ietf.jgss.GSSCredential;
  *
  * @author John Holman
  * @author Craig R. McClanahan
- * @version $Id: JNDIRealm.java 1138019 2011-06-21 14:29:49Z markt $
+ * @version $Id: JNDIRealm.java 1361774 2012-07-15 19:43:28Z markt $
  */
 
 public class JNDIRealm extends RealmBase {
@@ -298,6 +300,14 @@ public class JNDIRealm extends RealmBase {
      */
     protected String userPassword = null;
 
+    /**
+     * The name of the attribute inside the users
+     * directory entry where the value will be
+     * taken to search for roles
+     * This attribute is not used during a nested search
+     */
+    protected String userRoleAttribute = null;
+
 
     /**
      * A string of LDAP user patterns or paths, ":"-separated
@@ -359,7 +369,8 @@ public class JNDIRealm extends RealmBase {
 
     /**
      * The message format used to select roles for a user, with "{0}" marking
-     * the spot where the distinguished name of the user goes.
+     * the spot where the distinguished name of the user goes. The "{1}"
+     * and "{2}" are described in the Configuration Reference.
      */
     protected String roleSearch = null;
 
@@ -770,6 +781,14 @@ public class JNDIRealm extends RealmBase {
     }
 
 
+    public boolean isRoleSearchAsUser() {
+        return roleSearchAsUser;
+    }
+
+    public void setRoleSearchAsUser(boolean roleSearchAsUser) {
+        this.roleSearchAsUser = roleSearchAsUser;
+    }
+
     /**
      * Return the "search subtree for roles" flag.
      */
@@ -835,6 +854,14 @@ public class JNDIRealm extends RealmBase {
     }
 
 
+    public String getUserRoleAttribute() {
+        return userRoleAttribute;
+    }
+
+    public void setUserRoleAttribute(String userRoleAttribute) {
+        this.userRoleAttribute = userRoleAttribute;
+    }
+
     /**
      * Return the message format pattern for selecting users in this Realm.
      */
@@ -845,6 +872,8 @@ public class JNDIRealm extends RealmBase {
     }
 
 
+
+
     /**
      * Set the message format pattern for selecting users in this Realm.
      * This may be one simple pattern, or multiple patterns to be tried,
@@ -1249,6 +1278,9 @@ public class JNDIRealm extends RealmBase {
             list.add(userPassword);
         if (userRoleName != null)
             list.add(userRoleName);
+        if (userRoleAttribute != null) {
+            list.add(userRoleAttribute);
+        }
         String[] attrIds = new String[list.size()];
         list.toArray(attrIds);
 
@@ -1284,7 +1316,7 @@ public class JNDIRealm extends RealmBase {
 
         // If no attributes are requested, no need to look for them
         if (attrIds == null || attrIds.length == 0) {
-            return new User(username, dn, null, null);
+            return new User(username, dn, null, null,null);
         }
 
         // Get required attributes from user entry
@@ -1302,12 +1334,17 @@ public class JNDIRealm extends RealmBase {
         if (userPassword != null)
             password = getAttributeValue(userPassword, attrs);
 
+        String userRoleAttrValue = null;
+        if (userRoleAttribute != null) {
+            userRoleAttrValue = getAttributeValue(userRoleAttribute, attrs);
+        }
+
         // Retrieve values of userRoleName attribute
         ArrayList<String> roles = null;
         if (userRoleName != null)
             roles = addAttributeValues(userRoleName, attrs, roles);
 
-        return new User(username, dn, password, roles);
+        return new User(username, dn, password, roles, userRoleAttrValue);
     }
 
 
@@ -1446,12 +1483,17 @@ public class JNDIRealm extends RealmBase {
         if (userPassword != null)
             password = getAttributeValue(userPassword, attrs);
 
+        String userRoleAttrValue = null;
+        if (userRoleAttribute != null) {
+            userRoleAttrValue = getAttributeValue(userRoleAttribute, attrs);
+        }
+
         // Retrieve values of userRoleName attribute
         ArrayList<String> roles = null;
         if (userRoleName != null)
             roles = addAttributeValues(userRoleName, attrs, roles);
 
-        return new User(username, dn, password, roles);
+        return new User(username, dn, password, roles, userRoleAttrValue);
     }
 
 
@@ -1694,6 +1736,7 @@ public class JNDIRealm extends RealmBase {
 
         String dn = user.getDN();
         String username = user.getUserName();
+        String userRoleId = user.getUserRoleId();
 
         if (dn == null || username == null)
             return (null);
@@ -1721,7 +1764,7 @@ public class JNDIRealm extends RealmBase {
             return (list);
         
         // Set up parameters for an appropriate search
-        String filter = roleFormat.format(new String[] { doRFC2254Encoding(dn), username });
+        String filter = roleFormat.format(new String[] { doRFC2254Encoding(dn), username, userRoleId });
         SearchControls controls = new SearchControls();
         if (roleSubtree)
             controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
@@ -1794,7 +1837,7 @@ public class JNDIRealm extends RealmBase {
                 Map<String, String> newThisRound = new HashMap<String, String>(); // Stores the groups we find in this iteration
 
                 for (Entry<String, String> group : newGroups.entrySet()) {
-                    filter = roleFormat.format(new String[] { group.getKey(), group.getValue() });
+                    filter = roleFormat.format(new String[] { group.getKey(), group.getValue(), group.getValue() });
 
                     if (containerLog.isTraceEnabled()) {
                         containerLog.trace("Perform a nested group search with base "+ roleBase + " and filter " + filter);
@@ -2378,9 +2421,11 @@ public class JNDIRealm extends RealmBase {
         private final String dn;
         private final String password;
         private final List<String> roles;
+        private final String userRoleId;
+
 
         public User(String username, String dn, String password,
-                List<String> roles) {
+                List<String> roles, String userRoleId) {
             this.username = username;
             this.dn = dn;
             this.password = password;
@@ -2389,6 +2434,7 @@ public class JNDIRealm extends RealmBase {
             } else {
                 this.roles = Collections.unmodifiableList(roles);
             }
+            this.userRoleId = userRoleId;
         }
     
         public String getUserName() {
@@ -2406,6 +2452,12 @@ public class JNDIRealm extends RealmBase {
         public List<String> getRoles() {
             return roles;
         }
+
+        public String getUserRoleId() {
+            return userRoleId;
     }
+
+
+}
 }
 
diff --git a/java/org/apache/catalina/realm/MemoryRealm.java b/java/org/apache/catalina/realm/MemoryRealm.java
index 5172336..2e2c60f 100644
--- a/java/org/apache/catalina/realm/MemoryRealm.java
+++ b/java/org/apache/catalina/realm/MemoryRealm.java
@@ -43,7 +43,7 @@ import org.apache.tomcat.util.digester.Digester;
  * synchronization is performed around accesses to the principals collection.
  *
  * @author Craig R. McClanahan
- * @version $Id: MemoryRealm.java 1026786 2010-10-24 13:08:26Z markt $
+ * @version $Id: MemoryRealm.java 1361770 2012-07-15 19:38:51Z markt $
  */
 
 public class MemoryRealm  extends RealmBase {
@@ -266,7 +266,10 @@ public class MemoryRealm  extends RealmBase {
      * Returns the principals for this realm.
      *
      * @return The principals, keyed by user name (a String)
+     *
+     * @deprecated  Unused
      */
+    @Deprecated
     protected Map<String,GenericPrincipal> getPrincipals() {
         return principals;
     }
diff --git a/java/org/apache/catalina/realm/RealmBase.java b/java/org/apache/catalina/realm/RealmBase.java
index 5c8cb30..d69d7b0 100644
--- a/java/org/apache/catalina/realm/RealmBase.java
+++ b/java/org/apache/catalina/realm/RealmBase.java
@@ -45,7 +45,6 @@ import org.apache.catalina.Service;
 import org.apache.catalina.Wrapper;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
-import org.apache.catalina.deploy.LoginConfig;
 import org.apache.catalina.deploy.SecurityCollection;
 import org.apache.catalina.deploy.SecurityConstraint;
 import org.apache.catalina.mbeans.MBeanUtils;
@@ -68,7 +67,7 @@ import org.ietf.jgss.GSSName;
  * location) are identical to those currently supported by Tomcat 3.X.
  *
  * @author Craig R. McClanahan
- * @version $Id: RealmBase.java 1303339 2012-03-21 10:03:18Z markt $
+ * @version $Id: RealmBase.java 1379208 2012-08-30 22:59:07Z markt $
  */
 
 public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
@@ -119,7 +118,10 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
 
     /**
      * The MD5 helper object for this class.
+     *
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     protected static final MD5Encoder md5Encoder = new MD5Encoder();
 
 
@@ -426,7 +428,7 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
         String serverDigest = null;
         // Bugzilla 32137
         synchronized(md5Helper) {
-            serverDigest = md5Encoder.encode(md5Helper.digest(valueBytes));
+            serverDigest = MD5Encoder.encode(md5Helper.digest(valueBytes));
         }
 
         if (log.isDebugEnabled()) {
@@ -657,14 +659,15 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
                     }
                 }
                 if(matched) {
-                    found = true;
                     if(length > longest) {
+                        found = false;
                         if(results != null) {
                             results.clear();
                         }
                         longest = length;
                     }
                     if(collection[j].findMethod(method)) {
+                        found = true;
                         if(results == null) {
                             results = new ArrayList<SecurityConstraint>();
                         }
@@ -788,7 +791,7 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
      */
     private SecurityConstraint [] resultsToArray(
             ArrayList<SecurityConstraint> results) {
-        if(results == null) {
+        if(results == null || results.size() == 0) {
             return null;
         }
         SecurityConstraint [] array = new SecurityConstraint[results.size()];
@@ -819,31 +822,6 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
         if (constraints == null || constraints.length == 0)
             return (true);
 
-        // Specifically allow access to the form login and form error pages
-        // and the "j_security_check" action
-        LoginConfig config = context.getLoginConfig();
-        if ((config != null) &&
-            (Constants.FORM_METHOD.equals(config.getAuthMethod()))) {
-            String requestURI = request.getRequestPathMB().toString();
-            String loginPage = config.getLoginPage();
-            if (loginPage.equals(requestURI)) {
-                if (log.isDebugEnabled())
-                    log.debug(" Allow access to login page " + loginPage);
-                return (true);
-            }
-            String errorPage = config.getErrorPage();
-            if (errorPage.equals(requestURI)) {
-                if (log.isDebugEnabled())
-                    log.debug(" Allow access to error page " + errorPage);
-                return (true);
-            }
-            if (requestURI.endsWith(Constants.FORM_ACTION)) {
-                if (log.isDebugEnabled())
-                    log.debug(" Allow access to username/password submission");
-                return (true);
-            }
-        }
-
         // Which user principal have we already authenticated?
         Principal principal = request.getPrincipal();
         boolean status = false;
@@ -1227,7 +1205,7 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
             digest = md5Helper.digest(valueBytes);
         }
 
-        return md5Encoder.encode(digest);
+        return MD5Encoder.encode(digest);
     }
 
 
diff --git a/java/org/apache/catalina/security/SecurityClassLoad.java b/java/org/apache/catalina/security/SecurityClassLoad.java
index 62daafb..7031a2f 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 1347036 2012-06-06 18:32:43Z markt $
+ * @version $Id: SecurityClassLoad.java 1410548 2012-11-16 19:38:51Z markt $
  */
 
 public final class SecurityClassLoad {
@@ -43,6 +43,7 @@ public final class SecurityClassLoad {
         loadRealmPackage(loader);
         loadSessionPackage(loader);
         loadUtilPackage(loader);
+        loadValvesPackage(loader);
         loadJavaxPackage(loader);
         loadConnectorPackage(loader);
         loadTomcatPackage(loader);
@@ -54,6 +55,9 @@ public final class SecurityClassLoad {
         final String basePackage = "org.apache.catalina.core.";
         loader.loadClass
             (basePackage +
+             "AccessLogAdapter");
+        loader.loadClass
+            (basePackage +
              "ApplicationContextFacade$1");
         loader.loadClass
             (basePackage +
@@ -72,6 +76,12 @@ public final class SecurityClassLoad {
             "AsyncContextImpl$1");
         loader.loadClass
             (basePackage +
+            "AsyncContextImpl$PrivilegedGetTccl");
+        loader.loadClass
+            (basePackage +
+            "AsyncContextImpl$PrivilegedSetTccl");
+        loader.loadClass
+            (basePackage +
             "AsyncListenerWrapper");
         loader.loadClass
             (basePackage +
@@ -136,6 +146,13 @@ public final class SecurityClassLoad {
     }
 
 
+    private static final void loadValvesPackage(ClassLoader loader)
+            throws Exception {
+            final String basePackage = "org.apache.catalina.valves.";
+            loader.loadClass(basePackage + "AccessLogValve$3");
+        }
+
+
     private static final void loadCoyotePackage(ClassLoader loader)
             throws Exception {
         final String basePackage = "org.apache.coyote.";
@@ -251,23 +268,9 @@ public final class SecurityClassLoad {
                 basePackage + "util.http.FastHttpDateFormat");
         clazz.newInstance();
         loader.loadClass(basePackage + "util.http.HttpMessages");
-        loader.loadClass(basePackage + "util.http.parser.AstAttribute");
-        loader.loadClass(basePackage + "util.http.parser.AstMediaType");
-        loader.loadClass(basePackage + "util.http.parser.AstParameter");
-        loader.loadClass(basePackage + "util.http.parser.AstSubType");
-        loader.loadClass(basePackage + "util.http.parser.AstType");
-        loader.loadClass(basePackage + "util.http.parser.AstValue");
         loader.loadClass(basePackage + "util.http.parser.HttpParser");
-        loader.loadClass(basePackage + "util.http.parser.HttpParserConstants");
-        loader.loadClass(basePackage + "util.http.parser.HttpParserTokenManager");
-        loader.loadClass(basePackage + "util.http.parser.HttpParserTreeConstants");
-        loader.loadClass(basePackage + "util.http.parser.JJTHttpParserState");
-        loader.loadClass(basePackage + "util.http.parser.Node");
-        loader.loadClass(basePackage + "util.http.parser.ParseException");
-        loader.loadClass(basePackage + "util.http.parser.SimpleCharStream");
-        loader.loadClass(basePackage + "util.http.parser.SimpleNode");
-        loader.loadClass(basePackage + "util.http.parser.Token");
-        loader.loadClass(basePackage + "util.http.parser.TokenMgrError");
+        loader.loadClass(basePackage + "util.http.parser.MediaType");
+        loader.loadClass(basePackage + "util.http.parser.MediaTypeCache");
         // net
         loader.loadClass(basePackage + "util.net.Constants");
         loader.loadClass(basePackage +
diff --git a/java/org/apache/catalina/servlets/CGIServlet.java b/java/org/apache/catalina/servlets/CGIServlet.java
index 8b21fbc..518d8f6 100644
--- a/java/org/apache/catalina/servlets/CGIServlet.java
+++ b/java/org/apache/catalina/servlets/CGIServlet.java
@@ -233,7 +233,7 @@ import org.apache.catalina.util.IOTools;
  *
  * @author Martin T Dengler [root at martindengler.com]
  * @author Amy Roh
- * @version $Id: CGIServlet.java 1200163 2011-11-10 05:40:04Z kkolinko $
+ * @version $Id: CGIServlet.java 1402644 2012-10-26 20:02:24Z markt $
  * @since Tomcat 4.0
  *
  */
@@ -276,7 +276,7 @@ public final class CGIServlet extends HttpServlet {
     static Object expandFileLock = new Object();
 
     /** the shell environment variables to be passed to the CGI script */
-    static Hashtable<String,String> shellEnv = new Hashtable<String,String>();
+    Hashtable<String,String> shellEnv = new Hashtable<String,String>();
 
     /**
      * Sets instance variables.
@@ -646,7 +646,7 @@ public final class CGIServlet extends HttpServlet {
      * <p>
      * </p>
      *
-     * @version  $Id: CGIServlet.java 1200163 2011-11-10 05:40:04Z kkolinko $
+     * @version  $Id: CGIServlet.java 1402644 2012-10-26 20:02:24Z markt $
      * @since    Tomcat 4.0
      *
      */
@@ -1378,7 +1378,7 @@ public final class CGIServlet extends HttpServlet {
      * and <code>setResponse</code> methods, respectively.
      * </p>
      *
-     * @version $Id: CGIServlet.java 1200163 2011-11-10 05:40:04Z kkolinko $
+     * @version $Id: CGIServlet.java 1402644 2012-10-26 20:02:24Z markt $
      */
 
     protected class CGIRunner {
diff --git a/java/org/apache/catalina/servlets/WebdavServlet.java b/java/org/apache/catalina/servlets/WebdavServlet.java
index 358b919..a2fa1f3 100644
--- a/java/org/apache/catalina/servlets/WebdavServlet.java
+++ b/java/org/apache/catalina/servlets/WebdavServlet.java
@@ -128,7 +128,7 @@ import org.xml.sax.SAXException;
  * http://host:port/context/webdavedit/content
  *
  * @author Remy Maucherat
- * @version $Id: WebdavServlet.java 1239053 2012-02-01 10:52:00Z markt $
+ * @version $Id: WebdavServlet.java 1364451 2012-07-22 22:23:22Z markt $
  */
 
 public class WebdavServlet
@@ -211,7 +211,10 @@ public class WebdavServlet
 
     /**
      * The MD5 helper object for this class.
+     *
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     protected static final MD5Encoder md5Encoder = new MD5Encoder();
 
 
@@ -1152,7 +1155,7 @@ public class WebdavServlet
                 + lock.depth + "-" + lock.owner + "-" + lock.tokens + "-"
                 + lock.expiresAt + "-" + System.currentTimeMillis() + "-"
                 + secret;
-            String lockToken = md5Encoder.encode(md5Helper.digest(
+            String lockToken = MD5Encoder.encode(md5Helper.digest(
                     lockTokenStr.getBytes(Charset.defaultCharset())));
 
             if ( (exists) && (object instanceof DirContext) &&
diff --git a/java/org/apache/catalina/session/LocalStrings.properties b/java/org/apache/catalina/session/LocalStrings.properties
index c9ad121..7db05d4 100644
--- a/java/org/apache/catalina/session/LocalStrings.properties
+++ b/java/org/apache/catalina/session/LocalStrings.properties
@@ -80,4 +80,6 @@ persistentManager.processSwaps=Checking for sessions to swap out, {0} active ses
 persistentManager.activeSession=Session {0} has been idle for {1} seconds
 persistentManager.swapIn=Swapping session {0} in from Store
 persistentManager.swapInException=Exception in the Store during swapIn: {0}
-persistentManager.swapInInvalid=Swapped session {0} is invalid
\ No newline at end of file
+persistentManager.swapInInvalid=Swapped session {0} is invalid
+persistentManager.storeKeysException=Unable to determine the list of session IDs for sessions in the session store, assuming that the store is empty
+persistentManager.storeSizeException=Unable to determine the number of sessions in the session store, assuming that the store is empty
\ No newline at end of file
diff --git a/java/org/apache/catalina/session/PersistentManagerBase.java b/java/org/apache/catalina/session/PersistentManagerBase.java
index 2e60c24..8254abb 100644
--- a/java/org/apache/catalina/session/PersistentManagerBase.java
+++ b/java/org/apache/catalina/session/PersistentManagerBase.java
@@ -23,8 +23,11 @@ import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
+import org.apache.catalina.DistributedManager;
 import org.apache.catalina.Lifecycle;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.LifecycleState;
@@ -44,10 +47,11 @@ import org.apache.juli.logging.LogFactory;
  *
  * @author Craig R. McClanahan
  * @author Jean-Francois Arcand
- * @version $Id: PersistentManagerBase.java 1058571 2011-01-13 14:08:24Z markt $
+ * @version $Id: PersistentManagerBase.java 1402025 2012-10-25 08:47:08Z kfujino $
  */
 
-public abstract class PersistentManagerBase extends ManagerBase {
+public abstract class PersistentManagerBase extends ManagerBase
+        implements DistributedManager {
 
     private static final Log log = LogFactory.getLog(PersistentManagerBase.class);
 
@@ -646,9 +650,41 @@ public abstract class PersistentManagerBase extends ManagerBase {
     }
 
 
-    // ------------------------------------------------------ Protected Methods
+    @Override
+    public int getActiveSessionsFull() {
+        // In memory session count
+        int result = getActiveSessions();
+        try {
+            // Store session count
+            result += getStore().getSize();
+        } catch (IOException ioe) {
+            log.warn(sm.getString("persistentManager.storeSizeException"));
+        }
+        return result;
+    }
+
+
+    @Override
+    public Set<String> getSessionIdsFull() {
+        Set<String> sessionIds = new HashSet<String>();
+        // In memory session ID list
+        sessionIds.addAll(sessions.keySet());
+        // Store session ID list
+        String[] storeKeys;
+        try {
+            storeKeys = getStore().keys();
+            for (String storeKey : storeKeys) {
+                sessionIds.add(storeKey);
+            }
+        } catch (IOException e) {
+            log.warn(sm.getString("persistentManager.storeKeysException"));
+        }
+        return sessionIds;
+    }
 
 
+    // ------------------------------------------------------ Protected Methods
+
     /**
      * Look for a session in the Store and, if found, restore
      * it in the Manager's list of active sessions if appropriate.
@@ -884,8 +920,12 @@ public abstract class PersistentManagerBase extends ManagerBase {
                 synchronized (session) {
                     if (!session.isValid())
                         continue;
-                    int timeIdle = // Truncate, do not round up
-                        (int) ((timeNow - session.getThisAccessedTime()) / 1000L);
+                    int timeIdle;
+                    if (StandardSession.LAST_ACCESS_AT_START) {
+                        timeIdle = (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
+                    } else {
+                        timeIdle = (int) ((timeNow - session.getThisAccessedTime()) / 1000L);
+                    }
                     if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) {
                         if (session.accessCount != null &&
                                 session.accessCount.get() > 0) {
@@ -935,8 +975,12 @@ public abstract class PersistentManagerBase extends ManagerBase {
         for (int i = 0; i < sessions.length && toswap > 0; i++) {
             StandardSession session =  (StandardSession) sessions[i];
             synchronized (session) {
-                int timeIdle = // Truncate, do not round up
-                    (int) ((timeNow - session.getThisAccessedTime()) / 1000L);
+                int timeIdle;
+                if (StandardSession.LAST_ACCESS_AT_START) {
+                    timeIdle = (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
+                } else {
+                    timeIdle = (int) ((timeNow - session.getThisAccessedTime()) / 1000L);
+                }
                 if (timeIdle > minIdleSwap) {
                     if (session.accessCount != null &&
                             session.accessCount.get() > 0) {
@@ -979,8 +1023,12 @@ public abstract class PersistentManagerBase extends ManagerBase {
                 synchronized (session) {
                     if (!session.isValid())
                         continue;
-                    int timeIdle = // Truncate, do not round up
-                        (int) ((timeNow - session.getThisAccessedTime()) / 1000L);
+                    int timeIdle;
+                    if (StandardSession.LAST_ACCESS_AT_START) {
+                        timeIdle = (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
+                    } else {
+                        timeIdle = (int) ((timeNow - session.getThisAccessedTime()) / 1000L);
+                    }
                     if (timeIdle > maxIdleBackup) {
                         if (log.isDebugEnabled())
                             log.debug(sm.getString
diff --git a/java/org/apache/catalina/startup/Catalina.java b/java/org/apache/catalina/startup/Catalina.java
index d9ea7d0..9e170e4 100644
--- a/java/org/apache/catalina/startup/Catalina.java
+++ b/java/org/apache/catalina/startup/Catalina.java
@@ -67,7 +67,7 @@ import org.xml.sax.SAXParseException;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: Catalina.java 1333829 2012-05-04 09:46:59Z markt $
+ * @version $Id: Catalina.java 1364142 2012-07-21 18:29:12Z markt $
  */
 public class Catalina {
 
@@ -107,13 +107,19 @@ public class Catalina {
 
     /**
      * Are we starting a new server?
+     *
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     protected boolean starting = false;
 
 
     /**
      * Are we stopping an existing server?
+     *
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     protected boolean stopping = false;
 
 
@@ -144,7 +150,10 @@ public class Catalina {
 
     // ------------------------------------------------------------- Properties
 
-
+    /**
+     * @deprecated  Use {@link #setConfigFile(String)}
+     */
+    @Deprecated
     public void setConfig(String file) {
         configFile = file;
     }
diff --git a/java/org/apache/catalina/startup/CatalinaProperties.java b/java/org/apache/catalina/startup/CatalinaProperties.java
index b757dc7..556a7c1 100644
--- a/java/org/apache/catalina/startup/CatalinaProperties.java
+++ b/java/org/apache/catalina/startup/CatalinaProperties.java
@@ -32,7 +32,7 @@ import org.apache.catalina.Globals;
  * Utility class to read the bootstrap Catalina configuration.
  *
  * @author Remy Maucherat
- * @version $Id: CatalinaProperties.java 1075058 2011-02-27 14:12:39Z markt $
+ * @version $Id: CatalinaProperties.java 1364150 2012-07-21 18:57:54Z markt $
  */
 
 public class CatalinaProperties {
@@ -68,7 +68,10 @@ public class CatalinaProperties {
 
     /**
      * Return specified property value.
+     *
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static String getProperty(String name, String defaultValue) {
 
         return properties.getProperty(name, defaultValue);
diff --git a/java/org/apache/catalina/startup/Constants.java b/java/org/apache/catalina/startup/Constants.java
index 89ea665..fafb4e5 100644
--- a/java/org/apache/catalina/startup/Constants.java
+++ b/java/org/apache/catalina/startup/Constants.java
@@ -24,7 +24,7 @@ package org.apache.catalina.startup;
  *
  * @author Craig R. McClanahan
  * @author Jean-Francois Arcand
- * @version $Id: Constants.java 1138693 2011-06-22 23:39:58Z kkolinko $
+ * @version $Id: Constants.java 1377085 2012-08-24 20:21:07Z markt $
  */
 
 public final class Constants {
@@ -38,6 +38,13 @@ public final class Constants {
     public static final String HostContextXml = "context.xml.default";
     public static final String HostWebXml = "web.xml.default";
 
+    public static final String DEFAULT_JARS_TO_SKIP =
+            "tomcat.util.scan.DefaultJarScanner.jarsToSkip";
+    public static final String PLUGGABILITY_JARS_TO_SKIP =
+            "org.apache.catalina.startup.ContextConfig.jarsToSkip";
+    public static final String TLD_JARS_TO_SKIP =
+            "org.apache.catalina.startup.TldConfig.jarsToSkip";
+
     /**
      * A dummy value used to suppress loading the default web.xml file.
      *
diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java
index 6ea6f7c..fb056ca 100644
--- a/java/org/apache/catalina/startup/ContextConfig.java
+++ b/java/org/apache/catalina/startup/ContextConfig.java
@@ -5,9 +5,9 @@
  * 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.
@@ -41,6 +41,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.StringTokenizer;
 import java.util.concurrent.ConcurrentHashMap;
 
 import javax.naming.Binding;
@@ -108,12 +109,12 @@ import org.xml.sax.SAXParseException;
  *
  * @author Craig R. McClanahan
  * @author Jean-Francois Arcand
- * @version $Id: ContextConfig.java 1349008 2012-06-11 20:59:49Z markt $
+ * @version $Id: ContextConfig.java 1408166 2012-11-12 01:26:59Z markt $
  */
 public class ContextConfig implements LifecycleListener {
 
     private static final Log log = LogFactory.getLog( ContextConfig.class );
-    
+
     private static final String SCI_LOCATION =
         "META-INF/services/javax.servlet.ServletContainerInitializer";
 
@@ -128,7 +129,7 @@ public class ContextConfig implements LifecycleListener {
     protected static final LoginConfig DUMMY_LOGIN_CONFIG =
         new LoginConfig("NONE", null, null, null);
 
-    
+
 
     /**
      * The set of Authenticators that we know how to configure.  The key is
@@ -137,6 +138,14 @@ public class ContextConfig implements LifecycleListener {
      */
     protected static final Properties authenticators;
 
+    /**
+     * The list of JARs that will be skipped when scanning a web application
+     * for JARs. This means the JAR will not be scanned for web fragments, SCIs,
+     * annotations or classes that match @HandlesTypes.
+     */
+    private static final Set<String> pluggabilityJarsToSkip =
+            new HashSet<String>();
+
     static {
         // Load our mapping properties for the standard authenticators
         InputStream is =
@@ -152,8 +161,22 @@ public class ContextConfig implements LifecycleListener {
             }
         }
         authenticators = props;
+
+        // Load the list of JARS to skip
+        addJarsToSkip(Constants.DEFAULT_JARS_TO_SKIP);
+        addJarsToSkip(Constants.PLUGGABILITY_JARS_TO_SKIP);
     }
 
+    private static void addJarsToSkip(String systemPropertyName) {
+        String jarList = System.getProperty(systemPropertyName);
+        if (jarList != null) {
+            StringTokenizer tokenizer = new StringTokenizer(jarList, ",");
+            while (tokenizer.hasMoreElements()) {
+                pluggabilityJarsToSkip.add(tokenizer.nextToken());
+            }
+        }
+
+    }
 
     /**
      * Deployment count.
@@ -187,14 +210,14 @@ public class ContextConfig implements LifecycleListener {
      */
     @Deprecated
     protected String defaultContextXml = null;
-    
-    
+
+
     /**
      * The default web application's deployment descriptor location.
      */
     protected String defaultWebXml = null;
-    
-    
+
+
     /**
      * Track any fatal errors during startup configuration processing.
      */
@@ -205,14 +228,14 @@ public class ContextConfig implements LifecycleListener {
      * Original docBase.
      */
     protected String originalDocBase = null;
-    
+
 
     /**
      * Map of ServletContainerInitializer to classes they expressed interest in.
      */
     protected final Map<ServletContainerInitializer, Set<Class<?>>> initializerClassMap =
             new LinkedHashMap<ServletContainerInitializer, Set<Class<?>>>();
-    
+
     /**
      * Map of Types to ServletContainerInitializer that are interested in those
      * types.
@@ -254,7 +277,7 @@ public class ContextConfig implements LifecycleListener {
     protected Digester webFragmentDigester = null;
     protected WebRuleSet webFragmentRuleSet = null;
 
-    
+
     // ------------------------------------------------------------- Properties
     /**
      * Return the location of the default deployment descriptor
@@ -376,11 +399,11 @@ public class ContextConfig implements LifecycleListener {
      * Process the application classes annotations, if it exists.
      */
     protected void applicationAnnotationsConfig() {
-        
+
         long t1=System.currentTimeMillis();
-        
+
         WebAnnotationSet.loadApplicationAnnotations(context);
-        
+
         long t2=System.currentTimeMillis();
         if (context instanceof StandardContext) {
             ((StandardContext) context).setStartupTime(t2-t1+
@@ -415,7 +438,7 @@ public class ContextConfig implements LifecycleListener {
         // Has an authenticator been configured already?
         if (context.getAuthenticator() != null)
             return;
-        
+
         if (!(context instanceof ContainerBase)) {
             return;     // Cannot install a Valve even if it would be needed
         }
@@ -490,19 +513,19 @@ public class ContextConfig implements LifecycleListener {
      */
     public void createWebXmlDigester(boolean namespaceAware,
             boolean validation) {
-        
+
         webRuleSet = new WebRuleSet(false);
         webDigester = DigesterFactory.newDigester(validation,
                 namespaceAware, webRuleSet);
         webDigester.getParser();
-            
+
         webFragmentRuleSet = new WebRuleSet(true);
         webFragmentDigester = DigesterFactory.newDigester(validation,
                 namespaceAware, webFragmentRuleSet);
         webFragmentDigester.getParser();
     }
 
-    
+
     /**
      * Create (if necessary) and return a Digester configured to process the
      * context configuration descriptor for an application.
@@ -533,12 +556,12 @@ public class ContextConfig implements LifecycleListener {
         return System.getProperty(Globals.CATALINA_BASE_PROP);
     }
 
-    
+
     /**
      * Process the default configuration file, if it exists.
      */
     protected void contextConfig(Digester digester) {
-        
+
         // Open the default context.xml file, if it exists
         if( defaultContextXml==null && context instanceof StandardContext ) {
             defaultContextXml = ((StandardContext)context).getDefaultContextXml();
@@ -574,17 +597,17 @@ public class ContextConfig implements LifecycleListener {
         }
         if (context.getConfigFile() != null)
             processContextConfig(digester, context.getConfigFile());
-        
+
     }
 
-    
+
     /**
      * Process a context.xml.
      */
     protected void processContextConfig(Digester digester, URL contextXml) {
-        
+
         if (log.isDebugEnabled())
-            log.debug("Processing context [" + context.getName() 
+            log.debug("Processing context [" + context.getName()
                     + "] configuration file [" + contextXml + "]");
 
         InputSource source = null;
@@ -594,10 +617,10 @@ public class ContextConfig implements LifecycleListener {
             source = new InputSource(contextXml.toString());
             stream = contextXml.openStream();
         } catch (Exception e) {
-            log.error(sm.getString("contextConfig.contextMissing",  
+            log.error(sm.getString("contextConfig.contextMissing",
                       contextXml) , e);
         }
-        
+
         if (source == null)
             return;
 
@@ -641,13 +664,13 @@ public class ContextConfig implements LifecycleListener {
         }
     }
 
-    
+
     /**
      * Adjust docBase.
      */
     protected void fixDocBase()
         throws IOException {
-        
+
         Host host = (Host) context.getParent();
         String appBase = host.getAppBase();
 
@@ -655,7 +678,7 @@ public class ContextConfig implements LifecycleListener {
         if (canonicalAppBase.isAbsolute()) {
             canonicalAppBase = canonicalAppBase.getCanonicalFile();
         } else {
-            canonicalAppBase = 
+            canonicalAppBase =
                 new File(getBaseDir(), appBase)
                 .getCanonicalFile();
         }
@@ -679,7 +702,7 @@ public class ContextConfig implements LifecycleListener {
         }
         file = new File(docBase);
         String origDocBase = docBase;
-        
+
         ContextName cn = new ContextName(context.getPath(),
                 context.getWebappVersion());
         String pathName = cn.getBaseName();
@@ -740,13 +763,13 @@ public class ContextConfig implements LifecycleListener {
         context.setDocBase(docBase);
 
     }
-    
-    
+
+
     protected void antiLocking() {
 
-        if ((context instanceof StandardContext) 
+        if ((context instanceof StandardContext)
             && ((StandardContext) context).getAntiResourceLocking()) {
-            
+
             Host host = (Host) context.getParent();
             String appBase = host.getAppBase();
             String docBase = context.getDocBase();
@@ -765,7 +788,7 @@ public class ContextConfig implements LifecycleListener {
                 }
                 docBaseFile = new File(file, docBase);
             }
-            
+
             String path = context.getPath();
             if (path == null) {
                 return;
@@ -778,24 +801,24 @@ public class ContextConfig implements LifecycleListener {
                 file = new File(System.getProperty("java.io.tmpdir"),
                         deploymentCount++ + "-" + docBase + ".war");
             } else {
-                file = new File(System.getProperty("java.io.tmpdir"), 
+                file = new File(System.getProperty("java.io.tmpdir"),
                         deploymentCount++ + "-" + docBase);
             }
-            
+
             if (log.isDebugEnabled())
-                log.debug("Anti locking context[" + context.getName() 
+                log.debug("Anti locking context[" + context.getName()
                         + "] setting docBase to " + file);
-            
+
             // Cleanup just in case an old deployment is lying around
             ExpandWar.delete(file);
             if (ExpandWar.copy(docBaseFile, file)) {
                 context.setDocBase(file.getAbsolutePath());
             }
-            
+
         }
-        
+
     }
-    
+
 
     /**
      * Process a "init" event for this Context.
@@ -810,9 +833,9 @@ public class ContextConfig implements LifecycleListener {
             log.debug(sm.getString("contextConfig.init"));
         context.setConfigured(false);
         ok = true;
-        
+
         contextConfig(contextDigester);
-        
+
         createWebXmlDigester(context.getXmlNamespaceAware(),
                 context.getXmlValidation());
 
@@ -822,20 +845,20 @@ public class ContextConfig implements LifecycleListener {
             log.error(sm.getString(
                     "contextConfig.fixDocBase", context.getName()), e);
         }
-        
+
     }
-    
-    
+
+
     /**
      * Process a "before start" event for this Context.
      */
     protected synchronized void beforeStart() {
-        
+
         antiLocking();
 
     }
-    
-    
+
+
     /**
      * Process a "contextConfig" event for this Context.
      */
@@ -851,7 +874,7 @@ public class ContextConfig implements LifecycleListener {
                     Boolean.valueOf(context.getXmlValidation()),
                     Boolean.valueOf(context.getXmlNamespaceAware())));
         }
-        
+
         webConfig();
 
         if (!context.getIgnoreAnnotations()) {
@@ -1046,16 +1069,16 @@ public class ContextConfig implements LifecycleListener {
             // No need to log failure - it is expected in this case
             ExpandWar.delete(docBaseFile, false);
         }
-        
+
         // Reset ServletContextInitializer scanning
         initializerClassMap.clear();
         typeInitializerMap.clear();
-        
+
         ok = true;
 
     }
-    
-    
+
+
     /**
      * Process a "destroy" event for this Context.
      */
@@ -1069,30 +1092,33 @@ public class ContextConfig implements LifecycleListener {
         if (s != null && !s.getState().isAvailable()) {
             return;
         }
-        
+
         // Changed to getWorkPath per Bugzilla 35819.
-        String workDir = ((StandardContext) context).getWorkPath();
-        if (workDir != null)
-            ExpandWar.delete(new File(workDir));
+        if (context instanceof StandardContext) {
+            String workDir = ((StandardContext) context).getWorkPath();
+            if (workDir != null) {
+                ExpandWar.delete(new File(workDir));
+            }
+        }
     }
-    
-    
+
+
     private Server getServer() {
         Container c = context;
         while (c != null && !(c instanceof Engine)) {
             c = c.getParent();
         }
-        
+
         if (c == null) {
             return null;
         }
-        
+
         Service s = ((Engine)c).getService();
-        
+
         if (s == null) {
             return null;
         }
-        
+
         return s.getServer();
     }
 
@@ -1142,14 +1168,17 @@ public class ContextConfig implements LifecycleListener {
 
     /**
      * Get config base.
+     *
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     protected File getConfigBase() {
         File configBase = new File(getBaseDir(), "conf");
         if (!configBase.exists()) {
             return null;
         }
         return configBase;
-    }  
+    }
 
     protected File getHostConfigBase() {
         File file = null;
@@ -1195,13 +1224,31 @@ public class ContextConfig implements LifecycleListener {
      * web.xml file.
      */
     protected void webConfig() {
-        /* Anything and everything can override the global and host defaults.
+        /*
+         * Anything and everything can override the global and host defaults.
          * This is implemented in two parts
          * - Handle as a web fragment that gets added after everything else so
          *   everything else takes priority
          * - Mark Servlets as overridable so SCI configuration can replace
          *   configuration from the defaults
-         */ 
+         */
+
+        /*
+         * The rules for annotation scanning are not as clear-cut as one might
+         * think. Tomcat implements the following process:
+         * - As per SRV.1.6.2, Tomcat will scan for annotations regardless of
+         *   which Servlet spec version is declared in web.xml. The EG has
+         *   confirmed this is the expected behaviour.
+         * - As per http://java.net/jira/browse/SERVLET_SPEC-36, if the main
+         *   web.xml is marked as metadata-complete, JARs are still processed
+         *   for SCIs.
+         * - If metadata-complete=true and an absolute ordering is specified,
+         *   JARs excluded from the ordering are also excluded from the SCI
+         *   processing.
+         * - If an SCI has a @HandlesType annotation then all classes (except
+         *   those in JARs excluded from an absolute ordering) need to be
+         *   scanned to check if they match.
+         */
         Set<WebXml> defaults = new HashSet<WebXml>();
         defaults.add(getDefaultWebXmlFragment());
 
@@ -1210,163 +1257,154 @@ public class ContextConfig implements LifecycleListener {
         // Parse context level web.xml
         InputSource contextWebXml = getContextWebXmlSource();
         parseWebXml(contextWebXml, webXml, false);
-        
-        if (webXml.getMajorVersion() >= 3) {
-            ServletContext sContext = context.getServletContext();
-
-            // Ordering is important here
-
-            // Step 1. Identify all the JARs packaged with the application
-            // If the JARs have a web-fragment.xml it will be parsed at this
-            // point.
-            Map<String,WebXml> fragments = processJarsForWebFragments();
-
-            // Only need to process fragments and annotations if metadata is
-            // not complete
-            Set<WebXml> orderedFragments = null;
-            if  (!webXml.isMetadataComplete()) {
-                // Step 2. Order the fragments.
-                orderedFragments = WebXml.orderWebFragments(webXml, fragments);
-    
-                // Step 3. Look for ServletContainerInitializer implementations
-                if (ok) {
-                    processServletContainerInitializers(orderedFragments);
-                }
-    
-                // Step 4. Process /WEB-INF/classes for annotations
-                // This will add any matching classes to the typeInitializerMap
-                if (ok) {
-                    // Hack required by Eclipse's "serve modules without
-                    // publishing" feature since this backs WEB-INF/classes by
-                    // multiple locations rather than one.
-                    NamingEnumeration<Binding> listBindings = null;
+
+        ServletContext sContext = context.getServletContext();
+
+        // Ordering is important here
+
+        // Step 1. Identify all the JARs packaged with the application
+        // If the JARs have a web-fragment.xml it will be parsed at this
+        // point.
+        Map<String,WebXml> fragments = processJarsForWebFragments();
+
+        // Step 2. Order the fragments.
+        Set<WebXml> orderedFragments = null;
+        orderedFragments = WebXml.orderWebFragments(webXml, fragments);
+
+        // Step 3. Look for ServletContainerInitializer implementations
+        if (ok) {
+            processServletContainerInitializers(orderedFragments);
+        }
+
+        if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
+            // Step 4. Process /WEB-INF/classes for annotations
+            if (ok) {
+                // Hack required by Eclipse's "serve modules without
+                // publishing" feature since this backs WEB-INF/classes by
+                // multiple locations rather than one.
+                NamingEnumeration<Binding> listBindings = null;
+                try {
                     try {
-                        try {
-                            listBindings = context.getResources().listBindings(
-                                    "/WEB-INF/classes");
-                        } catch (NameNotFoundException ignore) {
-                            // Safe to ignore
-                        }
-                        while (listBindings != null &&
-                                listBindings.hasMoreElements()) {
-                            Binding binding = listBindings.nextElement();
-                            if (binding.getObject() instanceof FileDirContext) {
-                                File webInfClassDir = new File(
-                                        ((FileDirContext) binding.getObject()).getDocBase());
-                                processAnnotationsFile(webInfClassDir, webXml);
-                            } else {
-                                String resource =
-                                        "/WEB-INF/classes/" + binding.getName();
-                                try {
-                                    URL url = sContext.getResource(resource);
-                                    processAnnotationsUrl(url, webXml);
-                                } catch (MalformedURLException e) {
-                                    log.error(sm.getString(
-                                            "contextConfig.webinfClassesUrl",
-                                            resource), e);
-                                }
+                        listBindings = context.getResources().listBindings(
+                                "/WEB-INF/classes");
+                    } catch (NameNotFoundException ignore) {
+                        // Safe to ignore
+                    }
+                    while (listBindings != null &&
+                            listBindings.hasMoreElements()) {
+                        Binding binding = listBindings.nextElement();
+                        if (binding.getObject() instanceof FileDirContext) {
+                            File webInfClassDir = new File(
+                                    ((FileDirContext) binding.getObject()).getDocBase());
+                            processAnnotationsFile(webInfClassDir, webXml,
+                                    webXml.isMetadataComplete());
+                        } else {
+                            String resource =
+                                    "/WEB-INF/classes/" + binding.getName();
+                            try {
+                                URL url = sContext.getResource(resource);
+                                processAnnotationsUrl(url, webXml,
+                                        webXml.isMetadataComplete());
+                            } catch (MalformedURLException e) {
+                                log.error(sm.getString(
+                                        "contextConfig.webinfClassesUrl",
+                                        resource), e);
                             }
                         }
-                    } catch (NamingException e) {
-                        log.error(sm.getString(
-                                "contextConfig.webinfClassesUrl",
-                                "/WEB-INF/classes"), e);
-                    }
-                }
-    
-                // Step 5. Process JARs for annotations - only need to process
-                // those fragments we are going to use
-                // This will add any matching classes to the typeInitializerMap
-                if (ok) {
-                    processAnnotations(orderedFragments);
-                }
-    
-                // Cache, if used, is no longer required so clear it
-                javaClassCache.clear();
-
-                // Step 6. Merge web-fragment.xml files into the main web.xml
-                // file.
-                if (ok) {
-                    ok = webXml.merge(orderedFragments);
-                }
-    
-                // Step 7. Apply global defaults
-                // Have to merge defaults before JSP conversion since defaults
-                // provide JSP servlet definition.
-                webXml.merge(defaults);
-
-                // Step 8. Convert explicitly mentioned jsps to servlets
-                if (ok) {
-                    convertJsps(webXml);
-                }
-                
-                // Step 9. Apply merged web.xml to Context
-                if (ok) {
-                    webXml.configureContext(context);
-    
-                    // Step 9a. Make the merged web.xml available to other
-                    // components, specifically Jasper, to save those components
-                    // from having to re-generate it.
-                    // TODO Use a ServletContainerInitializer for Jasper
-                    String mergedWebXml = webXml.toXml();
-                    sContext.setAttribute(
-                           org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,
-                           mergedWebXml);
-                    if (context.getLogEffectiveWebXml()) {
-                        log.info("web.xml:\n" + mergedWebXml);
                     }
+                } catch (NamingException e) {
+                    log.error(sm.getString(
+                            "contextConfig.webinfClassesUrl",
+                            "/WEB-INF/classes"), e);
                 }
-            } else {
-                webXml.merge(defaults);
-                webXml.configureContext(context);
             }
-            
-            // Always need to look for static resources
-            // Step 10. Look for static resources packaged in JARs
+
+            // Step 5. Process JARs for annotations - only need to process
+            // those fragments we are going to use
             if (ok) {
-                // Spec does not define an order.
-                // Use ordered JARs followed by remaining JARs
-                Set<WebXml> resourceJars = new LinkedHashSet<WebXml>();
-                if (orderedFragments != null) {
-                    for (WebXml fragment : orderedFragments) {
-                        resourceJars.add(fragment);
-                    }
-                }
-                for (WebXml fragment : fragments.values()) {
-                    if (!resourceJars.contains(fragment)) {
-                        resourceJars.add(fragment);
-                    }
-                }
-                processResourceJARs(resourceJars);
-                // See also StandardContext.resourcesStart() for
-                // WEB-INF/classes/META-INF/resources configuration
-            }
-            
-            // Only look for ServletContainerInitializer if metadata is not
-            // complete
-            if (!webXml.isMetadataComplete()) {
-                // Step 11. Apply the ServletContainerInitializer config to the
-                // context
-                if (ok) {
-                    for (Map.Entry<ServletContainerInitializer,
-                            Set<Class<?>>> entry : 
-                                initializerClassMap.entrySet()) {
-                        if (entry.getValue().isEmpty()) {
-                            context.addServletContainerInitializer(
-                                    entry.getKey(), null);
-                        } else {
-                            context.addServletContainerInitializer(
-                                    entry.getKey(), entry.getValue());
-                        }
-                    }
-                }
+                processAnnotations(
+                        orderedFragments, webXml.isMetadataComplete());
+            }
+
+            // Cache, if used, is no longer required so clear it
+            javaClassCache.clear();
+        }
+
+        if (!webXml.isMetadataComplete()) {
+            // Step 6. Merge web-fragment.xml files into the main web.xml
+            // file.
+            if (ok) {
+                ok = webXml.merge(orderedFragments);
+            }
+
+            // Step 7. Apply global defaults
+            // Have to merge defaults before JSP conversion since defaults
+            // provide JSP servlet definition.
+            webXml.merge(defaults);
+
+            // Step 8. Convert explicitly mentioned jsps to servlets
+            if (ok) {
+                convertJsps(webXml);
+            }
+
+            // Step 9. Apply merged web.xml to Context
+            if (ok) {
+                webXml.configureContext(context);
             }
         } else {
-            // Apply unmerged web.xml to Context
             webXml.merge(defaults);
             convertJsps(webXml);
             webXml.configureContext(context);
         }
+
+        // Step 9a. Make the merged web.xml available to other
+        // components, specifically Jasper, to save those components
+        // from having to re-generate it.
+        // TODO Use a ServletContainerInitializer for Jasper
+        String mergedWebXml = webXml.toXml();
+        sContext.setAttribute(
+               org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,
+               mergedWebXml);
+        if (context.getLogEffectiveWebXml()) {
+            log.info("web.xml:\n" + mergedWebXml);
+        }
+
+        // Always need to look for static resources
+        // Step 10. Look for static resources packaged in JARs
+        if (ok) {
+            // Spec does not define an order.
+            // Use ordered JARs followed by remaining JARs
+            Set<WebXml> resourceJars = new LinkedHashSet<WebXml>();
+            if (orderedFragments != null) {
+                for (WebXml fragment : orderedFragments) {
+                    resourceJars.add(fragment);
+                }
+            }
+            for (WebXml fragment : fragments.values()) {
+                if (!resourceJars.contains(fragment)) {
+                    resourceJars.add(fragment);
+                }
+            }
+            processResourceJARs(resourceJars);
+            // See also StandardContext.resourcesStart() for
+            // WEB-INF/classes/META-INF/resources configuration
+        }
+
+        // Step 11. Apply the ServletContainerInitializer config to the
+        // context
+        if (ok) {
+            for (Map.Entry<ServletContainerInitializer,
+                    Set<Class<?>>> entry :
+                        initializerClassMap.entrySet()) {
+                if (entry.getValue().isEmpty()) {
+                    context.addServletContainerInitializer(
+                            entry.getKey(), null);
+                } else {
+                    context.addServletContainerInitializer(
+                            entry.getKey(), entry.getValue());
+                }
+            }
+        }
     }
 
     private WebXml getDefaultWebXmlFragment() {
@@ -1375,13 +1413,13 @@ public class ContextConfig implements LifecycleListener {
         Host host = (Host) context.getParent();
 
         DefaultWebXmlCacheEntry entry = hostWebXmlCache.get(host);
-        
+
         InputSource globalWebXml = getGlobalWebXmlSource();
         InputSource hostWebXml = getHostWebXmlSource();
-        
+
         long globalTimeStamp = 0;
         long hostTimeStamp = 0;
-        
+
         if (globalWebXml != null) {
             try {
                 URL url = new URL(globalWebXml.getSystemId());
@@ -1392,7 +1430,7 @@ public class ContextConfig implements LifecycleListener {
                 globalTimeStamp = -1;
             }
         }
-        
+
         if (hostWebXml != null) {
             try {
                 URL url = new URL(hostWebXml.getSystemId());
@@ -1403,12 +1441,12 @@ public class ContextConfig implements LifecycleListener {
                 hostTimeStamp = -1;
             }
         }
-        
+
         if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
                 entry.getHostTimeStamp() == hostTimeStamp) {
             return entry.getWebXml();
         }
-        
+
         // Parsing global web.xml is relatively expensive. Use a sync block to
         // make sure it only happens once. Use the pipeline since a lock will
         // already be held on the host by another thread
@@ -1436,13 +1474,13 @@ public class ContextConfig implements LifecycleListener {
             } else {
                 parseWebXml(globalWebXml, webXmlDefaultFragment, false);
             }
-            
+
             // Parse host level web.xml if present
             // Additive apart from welcome pages
             webXmlDefaultFragment.setReplaceWelcomeFiles(true);
-            
+
             parseWebXml(hostWebXml, webXmlDefaultFragment, false);
-            
+
             // Don't update the cache if an error occurs
             if (globalTimeStamp != -1 && hostTimeStamp != -1) {
                 entry = new DefaultWebXmlCacheEntry(webXmlDefaultFragment,
@@ -1509,7 +1547,7 @@ public class ContextConfig implements LifecycleListener {
      */
     protected void processServletContainerInitializers(
             Set<WebXml> fragments) {
-        
+
         for (WebXml fragment : fragments) {
             URL url = fragment.getURL();
             Jar jar = null;
@@ -1547,13 +1585,13 @@ public class ContextConfig implements LifecycleListener {
                     jar.close();
                 }
             }
-            
+
             if (sci == null) {
                 continue;
             }
 
             initializerClassMap.put(sci, new HashSet<Class<?>>());
-            
+
             HandlesTypes ht = null;
             try {
                 ht = sci.getClass().getAnnotation(HandlesTypes.class);
@@ -1586,12 +1624,12 @@ public class ContextConfig implements LifecycleListener {
 
         }
     }
-    
-    
+
+
     /**
      * Extract the name of the ServletContainerInitializer.
-     * 
-     * @param is    The resource where the name is defined 
+     *
+     * @param is    The resource where the name is defined
      * @return      The class name
      * @throws IOException
      */
@@ -1599,7 +1637,7 @@ public class ContextConfig implements LifecycleListener {
             InputStream is) throws IOException {
 
         String className = null;
-        
+
         if (is != null) {
             String line = null;
             try {
@@ -1614,7 +1652,7 @@ public class ContextConfig implements LifecycleListener {
                 // If it does - ignore & return null
             }
         }
-        
+
         ServletContainerInitializer sci = null;
         try {
             Class<?> clazz = Class.forName(className,true,
@@ -1630,11 +1668,11 @@ public class ContextConfig implements LifecycleListener {
             log.error(sm.getString("contextConfig.invalidSci", className), e);
             throw new IOException(e);
         }
-        
+
         return sci;
     }
 
-    
+
     /**
      * Scan JARs that contain web-fragment.xml files that will be used to
      * configure this application to see if they also contain static resources.
@@ -1649,8 +1687,15 @@ public class ContextConfig implements LifecycleListener {
                 // Note: Ignore file URLs for now since only jar URLs will be accepted
                 if ("jar".equals(url.getProtocol())) {
                     jar = JarFactory.newInstance(url);
-                    if (jar.entryExists("META-INF/resources/")) {
-                        context.addResourceJarUrl(url);
+                    jar.nextEntry();
+                    String entryName = jar.getEntryName();
+                    while (entryName != null) {
+                        if (entryName.startsWith("META-INF/resources/")) {
+                            context.addResourceJarUrl(url);
+                            break;
+                        }
+                        jar.nextEntry();
+                        entryName = jar.getEntryName();
                     }
                 } else if ("file".equals(url.getProtocol())) {
                     FileDirContext fileDirContext = new FileDirContext();
@@ -1678,8 +1723,8 @@ public class ContextConfig implements LifecycleListener {
             }
         }
     }
-    
-    
+
+
     /**
      * Identify the default web.xml to be used and obtain an input source for
      * it.
@@ -1711,7 +1756,7 @@ public class ContextConfig implements LifecycleListener {
 
         return getWebXmlSource(Constants.HostWebXml, hostConfigBase.getPath());
     }
-    
+
     /**
      * Identify the application web.xml to be used and obtain an input source
      * for it.
@@ -1720,7 +1765,7 @@ public class ContextConfig implements LifecycleListener {
         InputStream stream = null;
         InputSource source = null;
         URL url = null;
-        
+
         String altDDName = null;
 
         // Open the application web.xml file, if it exists
@@ -1758,15 +1803,15 @@ public class ContextConfig implements LifecycleListener {
             source = new InputSource(url.toExternalForm());
             source.setByteStream(stream);
         }
-        
+
         return source;
     }
-    
+
     /**
-     * 
+     *
      * @param filename  Name of the file (possibly with one or more leading path
      *                  segments) to read
-     * @param path      Location that filename is relative to 
+     * @param path      Location that filename is relative to
      */
     protected InputSource getWebXmlSource(String filename, String path) {
         File file = new File(filename);
@@ -1786,7 +1831,7 @@ public class ContextConfig implements LifecycleListener {
                     source =
                         new InputSource(getClass().getClassLoader().getResource(
                                 filename).toURI().toString());
-                } 
+                }
             } else {
                 source = new InputSource(file.getAbsoluteFile().toURI().toString());
                 stream = new FileInputStream(file);
@@ -1806,7 +1851,7 @@ public class ContextConfig implements LifecycleListener {
 
     protected void parseWebXml(InputSource source, WebXml dest,
             boolean fragment) {
-        
+
         if (source == null) return;
 
         XmlErrorHandler handler = new XmlErrorHandler();
@@ -1820,15 +1865,15 @@ public class ContextConfig implements LifecycleListener {
             digester = webDigester;
             ruleSet = webRuleSet;
         }
-        
+
         digester.push(dest);
         digester.setErrorHandler(handler);
-            
+
         if(log.isDebugEnabled()) {
             log.debug(sm.getString("contextConfig.applicationStart",
                     source.getSystemId()));
         }
-            
+
         try {
             digester.parse(source);
 
@@ -1856,52 +1901,55 @@ public class ContextConfig implements LifecycleListener {
 
 
     /**
-     * Scan /META-INF/lib for JARs and for each one found add it and any
+     * Scan /WEB-INF/lib for JARs and for each one found add it and any
      * /META-INF/web-fragment.xml to the resulting Map. web-fragment.xml files
      * will be parsed before being added to the map. Every JAR will be added and
      * <code>null</code> will be used if no web-fragment.xml was found. Any JARs
      * known not contain fragments will be skipped.
-     * 
+     *
      * @return A map of JAR name to processed web fragment (if any)
      */
     protected Map<String,WebXml> processJarsForWebFragments() {
-        
+
         JarScanner jarScanner = context.getJarScanner();
         FragmentJarScannerCallback callback = new FragmentJarScannerCallback();
-        
+
         jarScanner.scan(context.getServletContext(),
-                context.getLoader().getClassLoader(), callback, null);
-        
+                context.getLoader().getClassLoader(), callback,
+                pluggabilityJarsToSkip);
+
         return callback.getFragments();
     }
 
-    protected void processAnnotations(Set<WebXml> fragments) {
+    protected void processAnnotations(Set<WebXml> fragments,
+            boolean handlesTypesOnly) {
         for(WebXml fragment : fragments) {
-            if (!fragment.isMetadataComplete()) {
-                WebXml annotations = new WebXml();
-                // no impact on distributable
-                annotations.setDistributable(true);
-                URL url = fragment.getURL();
-                processAnnotationsUrl(url, annotations);
-                Set<WebXml> set = new HashSet<WebXml>();
-                set.add(annotations);
-                // Merge annotations into fragment - fragment takes priority
-                fragment.merge(set);
-            }
+            WebXml annotations = new WebXml();
+            // no impact on distributable
+            annotations.setDistributable(true);
+            URL url = fragment.getURL();
+            processAnnotationsUrl(url, annotations,
+                    (handlesTypesOnly || fragment.isMetadataComplete()));
+            Set<WebXml> set = new HashSet<WebXml>();
+            set.add(annotations);
+            // Merge annotations into fragment - fragment takes priority
+            fragment.merge(set);
         }
     }
 
-    protected void processAnnotationsUrl(URL url, WebXml fragment) {
+    protected void processAnnotationsUrl(URL url, WebXml fragment,
+            boolean handlesTypesOnly) {
         if (url == null) {
             // Nothing to do.
             return;
         } else if ("jar".equals(url.getProtocol())) {
-            processAnnotationsJar(url, fragment);
+            processAnnotationsJar(url, fragment, handlesTypesOnly);
         } else if ("jndi".equals(url.getProtocol())) {
-            processAnnotationsJndi(url, fragment);
+            processAnnotationsJndi(url, fragment, handlesTypesOnly);
         } else if ("file".equals(url.getProtocol())) {
             try {
-                processAnnotationsFile(new File(url.toURI()), fragment);
+                processAnnotationsFile(
+                        new File(url.toURI()), fragment, handlesTypesOnly);
             } catch (URISyntaxException e) {
                 log.error(sm.getString("contextConfig.fileUrl", url), e);
             }
@@ -1909,18 +1957,19 @@ public class ContextConfig implements LifecycleListener {
             log.error(sm.getString("contextConfig.unknownUrlProtocol",
                     url.getProtocol(), url));
         }
-        
+
     }
 
 
-    protected void processAnnotationsJar(URL url, WebXml fragment) {
+    protected void processAnnotationsJar(URL url, WebXml fragment,
+            boolean handlesTypesOnly) {
 
         Jar jar = null;
         InputStream is;
-        
+
         try {
             jar = JarFactory.newInstance(url);
-            
+
             jar.nextEntry();
             String entryName = jar.getEntryName();
             while (entryName != null) {
@@ -1928,7 +1977,8 @@ public class ContextConfig implements LifecycleListener {
                     is = null;
                     try {
                         is = jar.getEntryInputStream();
-                        processAnnotationsStream(is, fragment);
+                        processAnnotationsStream(
+                                is, fragment, handlesTypesOnly);
                     } catch (IOException e) {
                         log.error(sm.getString("contextConfig.inputStreamJar",
                                 entryName, url),e);
@@ -1957,8 +2007,9 @@ public class ContextConfig implements LifecycleListener {
         }
     }
 
-    
-    protected void processAnnotationsJndi(URL url, WebXml fragment) {
+
+    protected void processAnnotationsJndi(URL url, WebXml fragment,
+            boolean handlesTypesOnly) {
         try {
             URLConnection urlConn = url.openConnection();
             DirContextURLConnection dcUrlConn;
@@ -1967,10 +2018,10 @@ public class ContextConfig implements LifecycleListener {
                 sm.getString("contextConfig.jndiUrlNotDirContextConn", url);
                 return;
             }
-            
+
             dcUrlConn = (DirContextURLConnection) urlConn;
             dcUrlConn.setUseCaches(false);
-            
+
             String type = dcUrlConn.getHeaderField(ResourceAttributes.TYPE);
             if (ResourceAttributes.COLLECTION_TYPE.equals(type)) {
                 // Collection
@@ -1978,16 +2029,17 @@ public class ContextConfig implements LifecycleListener {
                 while (dirs.hasMoreElements()) {
                     String dir = dirs.nextElement();
                     URL dirUrl = new URL(url.toString() + '/' + dir);
-                    processAnnotationsJndi(dirUrl, fragment);
+                    processAnnotationsJndi(dirUrl, fragment, handlesTypesOnly);
                 }
-                
+
             } else {
                 // Single file
                 if (url.getPath().endsWith(".class")) {
                     InputStream is = null;
                     try {
                         is = dcUrlConn.getInputStream();
-                        processAnnotationsStream(is, fragment);
+                        processAnnotationsStream(
+                                is, fragment, handlesTypesOnly);
                     } catch (IOException e) {
                         log.error(sm.getString("contextConfig.inputStreamJndi",
                                 url),e);
@@ -2009,20 +2061,22 @@ public class ContextConfig implements LifecycleListener {
             log.error(sm.getString("contextConfig.jndiUrl", url), e);
         }
     }
-    
-    
-    protected void processAnnotationsFile(File file, WebXml fragment) {
-        
+
+
+    protected void processAnnotationsFile(File file, WebXml fragment,
+            boolean handlesTypesOnly) {
+
         if (file.isDirectory()) {
             String[] dirs = file.list();
             for (String dir : dirs) {
-                processAnnotationsFile(new File(file,dir), fragment);
+                processAnnotationsFile(
+                        new File(file,dir), fragment, handlesTypesOnly);
             }
         } else if (file.canRead() && file.getName().endsWith(".class")) {
             FileInputStream fis = null;
             try {
                 fis = new FileInputStream(file);
-                processAnnotationsStream(fis, fragment);
+                processAnnotationsStream(fis, fragment, handlesTypesOnly);
             } catch (IOException e) {
                 log.error(sm.getString("contextConfig.inputStreamFile",
                         file.getAbsolutePath()),e);
@@ -2042,16 +2096,21 @@ public class ContextConfig implements LifecycleListener {
     }
 
 
-    protected void processAnnotationsStream(InputStream is, WebXml fragment)
+    protected void processAnnotationsStream(InputStream is, WebXml fragment,
+            boolean handlesTypesOnly)
             throws ClassFormatException, IOException {
-        
+
         ClassParser parser = new ClassParser(is, null);
         JavaClass clazz = parser.parse();
-        
+
         checkHandlesTypes(clazz);
-        
+
+        if (handlesTypesOnly) {
+            return;
+        }
+
         String className = clazz.getClassName();
-        
+
         AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries();
 
         for (AnnotationEntry ae : annotationsEntries) {
@@ -2075,11 +2134,11 @@ public class ContextConfig implements LifecycleListener {
      * @param javaClass
      */
     protected void checkHandlesTypes(JavaClass javaClass) {
-        
+
         // Skip this if we can
         if (typeInitializerMap.size() == 0)
             return;
-        
+
         if ((javaClass.getAccessFlags() &
                 org.apache.tomcat.util.bcel.Constants.ACC_ANNOTATION) > 0) {
             // Skip annotations.
@@ -2087,7 +2146,7 @@ public class ContextConfig implements LifecycleListener {
         }
 
         String className = javaClass.getClassName();
-        
+
         Class<?> clazz = null;
         if (handlesTypesNonAnnotations) {
             // This *might* be match for a HandlesType.
@@ -2187,10 +2246,8 @@ public class ContextConfig implements LifecycleListener {
         Set<ServletContainerInitializer> result =
                 new HashSet<ServletContainerInitializer>();
 
-        JavaClass javaClass = cacheEntry.getJavaClass();
-
         // Super class
-        String superClassName = javaClass.getSuperclassName();
+        String superClassName = cacheEntry.getSuperclassName();
         JavaClassCacheEntry superClassCacheEntry =
                 javaClassCache.get(superClassName);
 
@@ -2210,7 +2267,7 @@ public class ContextConfig implements LifecycleListener {
         result.addAll(getSCIsForClass(superClassName));
 
         // Interfaces
-        for (String interfaceName : javaClass.getInterfaceNames()) {
+        for (String interfaceName : cacheEntry.getInterfaceNames()) {
             JavaClassCacheEntry interfaceEntry =
                     javaClassCache.get(interfaceName);
             // A null could mean that the class not present in application or
@@ -2245,7 +2302,7 @@ public class ContextConfig implements LifecycleListener {
         if (!internalForm.startsWith("L")) {
             return internalForm;
         }
-        
+
         // Assume starts with L, ends with ; and uses / rather than .
         return internalForm.substring(1,
                 internalForm.length() - 1).replace('/', '.');
@@ -2268,7 +2325,7 @@ public class ContextConfig implements LifecycleListener {
             servletName = className;
         }
         ServletDef servletDef = fragment.getServlets().get(servletName);
-        
+
         boolean isWebXMLservletDef;
         if (servletDef == null) {
             servletDef = new ServletDef();
@@ -2515,7 +2572,7 @@ public class ContextConfig implements LifecycleListener {
         String[] result = new String[values.size()];
         return values.toArray(result);
     }
-    
+
     protected Map<String,String> processAnnotationWebInitParams(
             ElementValue ev) {
         Map<String, String> result = new HashMap<String,String>();
@@ -2543,16 +2600,16 @@ public class ContextConfig implements LifecycleListener {
         }
         return result;
     }
-    
+
     private class FragmentJarScannerCallback implements JarScannerCallback {
 
         private static final String FRAGMENT_LOCATION =
             "META-INF/web-fragment.xml";
         private Map<String,WebXml> fragments = new HashMap<String,WebXml>();
-        
+
         @Override
         public void scan(JarURLConnection jarConn) throws IOException {
-            
+
             URL url = jarConn.getURL();
             URL resourceURL = jarConn.getJarFileURL();
             Jar jar = null;
@@ -2597,7 +2654,7 @@ public class ContextConfig implements LifecycleListener {
 
             InputStream stream = null;
             WebXml fragment = new WebXml();
-            
+
             try {
                 File fragmentFile = new File(file, FRAGMENT_LOCATION);
                 if (fragmentFile.isFile()) {
@@ -2622,7 +2679,7 @@ public class ContextConfig implements LifecycleListener {
                 fragments.put(fragment.getName(), fragment);
             }
         }
-        
+
         public Map<String,WebXml> getFragments() {
             return fragments;
         }
@@ -2654,15 +2711,23 @@ public class ContextConfig implements LifecycleListener {
     }
 
     private static class JavaClassCacheEntry {
-        private final JavaClass javaClass;
+        public final String superclassName;
+
+        public final String[] interfaceNames;
+
         private Set<ServletContainerInitializer> sciSet = null;
 
         public JavaClassCacheEntry(JavaClass javaClass) {
-            this.javaClass = javaClass;
+            superclassName = javaClass.getSuperclassName();
+            interfaceNames = javaClass.getInterfaceNames();
+        }
+
+        public String getSuperclassName() {
+            return superclassName;
         }
 
-        public JavaClass getJavaClass() {
-            return javaClass;
+        public String[] getInterfaceNames() {
+            return interfaceNames;
         }
 
         public Set<ServletContainerInitializer> getSciSet() {
diff --git a/java/org/apache/catalina/startup/DigesterFactory.java b/java/org/apache/catalina/startup/DigesterFactory.java
index c8ae586..8b657cd 100644
--- a/java/org/apache/catalina/startup/DigesterFactory.java
+++ b/java/org/apache/catalina/startup/DigesterFactory.java
@@ -40,7 +40,10 @@ public class DigesterFactory {
     /**
      * Create a <code>Digester</code> parser with no <code>Rule</code>
      * associated and XML validation turned off.
+     *
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static Digester newDigester(){
         return newDigester(false, false, null);
     }
@@ -49,7 +52,10 @@ public class DigesterFactory {
     /**
      * Create a <code>Digester</code> parser with XML validation turned off.
      * @param rule an instance of <code>RuleSet</code> used for parsing the xml.
+     *
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static Digester newDigester(RuleSet rule){
         return newDigester(false,false,rule);
     }
diff --git a/java/org/apache/catalina/startup/ExpandWar.java b/java/org/apache/catalina/startup/ExpandWar.java
index 5175004..742227e 100644
--- a/java/org/apache/catalina/startup/ExpandWar.java
+++ b/java/org/apache/catalina/startup/ExpandWar.java
@@ -45,7 +45,7 @@ import org.apache.tomcat.util.res.StringManager;
  * @author Craig R. McClanahan
  * @author Remy Maucherat
  * @author Glenn L. Nielsen
- * @version $Revision: 1173343 $
+ * @version $Revision: 1359986 $
  */
 
 public class ExpandWar {
@@ -96,7 +96,8 @@ public class ExpandWar {
         }
 
         // Create the new document base directory
-        docBase.mkdir();
+        if(!docBase.mkdir() && !docBase.isDirectory())
+            throw new IOException(sm.getString("expandWar.createFailed", docBase));
 
         // Expand the WAR into the new document base directory
         String canonicalDocBasePrefix = docBase.getCanonicalPath();
diff --git a/java/org/apache/catalina/startup/FailedContext.java b/java/org/apache/catalina/startup/FailedContext.java
index 409783b..ba5b162 100644
--- a/java/org/apache/catalina/startup/FailedContext.java
+++ b/java/org/apache/catalina/startup/FailedContext.java
@@ -181,6 +181,10 @@ public class FailedContext extends LifecycleMBeanBase implements Context {
     @Override
     public void removeChild(Container child) { /* NO-OP */ }
 
+    @Override
+    public String toString() {
+        return getName();
+    }
 
     // -------------------------------------------- All NO-OPs beyond this point
     @Override
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index 8737095..575420c 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -5,9 +5,9 @@
  * 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.
@@ -28,11 +28,14 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
@@ -45,12 +48,14 @@ import javax.management.ObjectName;
 
 import org.apache.catalina.Container;
 import org.apache.catalina.Context;
+import org.apache.catalina.DistributedManager;
 import org.apache.catalina.Engine;
 import org.apache.catalina.Globals;
 import org.apache.catalina.Host;
 import org.apache.catalina.Lifecycle;
 import org.apache.catalina.LifecycleEvent;
 import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
 import org.apache.catalina.core.StandardHost;
 import org.apache.catalina.util.ContextName;
 import org.apache.catalina.util.IOTools;
@@ -68,11 +73,11 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: HostConfig.java 1343337 2012-05-28 17:50:14Z kkolinko $
+ * @version $Id: HostConfig.java 1408166 2012-11-12 01:26:59Z markt $
  */
 public class HostConfig
     implements LifecycleListener {
-    
+
     private static final Log log = LogFactory.getLog( HostConfig.class );
 
     // ----------------------------------------------------- Instance Variables
@@ -107,12 +112,12 @@ public class HostConfig
      */
     protected Host host = null;
 
-    
+
     /**
      * The JMX ObjectName of this component.
      */
     protected ObjectName oname = null;
-    
+
 
     /**
      * The string resources for this package.
@@ -134,8 +139,8 @@ public class HostConfig
      * a web application is deployed?
      */
     protected boolean copyXML = false;
-    
-    
+
+
     /**
      * Should we unpack WAR files when auto-deploying applications in the
      * <code>appBase</code> directory?
@@ -149,13 +154,13 @@ public class HostConfig
     protected Map<String, DeployedApplication> deployed =
         new ConcurrentHashMap<String, DeployedApplication>();
 
-    
+
     /**
-     * List of applications which are being serviced, and shouldn't be 
+     * List of applications which are being serviced, and shouldn't be
      * deployed/undeployed/redeployed at the moment.
      */
     protected ArrayList<String> serviced = new ArrayList<String>();
-    
+
 
     /**
      * The <code>Digester</code> instance used to parse context descriptors.
@@ -279,8 +284,8 @@ public class HostConfig
         this.unpackWARs = unpackWARs;
 
     }
-    
-    
+
+
     // --------------------------------------------------------- Public Methods
 
 
@@ -316,15 +321,15 @@ public class HostConfig
 
     }
 
-    
+
     /**
      * Add a serviced application to the list.
      */
     public synchronized void addServiced(String name) {
         serviced.add(name);
     }
-    
-    
+
+
     /**
      * Is application serviced ?
      * @return state of the application
@@ -332,7 +337,7 @@ public class HostConfig
     public synchronized boolean isServiced(String name) {
         return (serviced.contains(name));
     }
-    
+
 
     /**
      * Removed a serviced application from the list.
@@ -341,7 +346,7 @@ public class HostConfig
         serviced.remove(name);
     }
 
-    
+
     /**
      * Get the instant where an application was deployed.
      * @return 0L if no application with that name is deployed, or the instant
@@ -352,11 +357,11 @@ public class HostConfig
         if (app == null) {
             return 0L;
         }
-        
+
         return app.timestamp;
     }
-    
-    
+
+
     /**
      * Has the specified application been deployed? Note applications defined
      * in server.xml will not have been deployed.
@@ -369,14 +374,14 @@ public class HostConfig
         if (app == null) {
             return false;
         }
-        
+
         return true;
     }
-    
-    
+
+
     // ------------------------------------------------------ Protected Methods
 
-    
+
     /**
      * Create the digester which will be used to parse context config files.
      */
@@ -386,12 +391,12 @@ public class HostConfig
         // Add object creation rule
         digester.addObjectCreate("Context", "org.apache.catalina.core.StandardContext",
             "className");
-        // Set the properties on that object (it doesn't matter if extra 
+        // Set the properties on that object (it doesn't matter if extra
         // properties are set)
         digester.addSetProperties("Context");
         return (digester);
     }
-    
+
     protected File returnCanonicalPath(String path) {
         File file = new File(path);
         File base = new File(System.getProperty(Globals.CATALINA_BASE_PROP));
@@ -403,7 +408,7 @@ public class HostConfig
             return file;
         }
     }
-    
+
 
     /**
      * Return a File object representing the "application root" directory
@@ -414,7 +419,7 @@ public class HostConfig
         if (appBase != null) {
             return appBase;
         }
-        
+
         appBase = returnCanonicalPath(host.getAppBase());
         return appBase;
 
@@ -430,7 +435,7 @@ public class HostConfig
         if (configBase != null) {
             return configBase;
         }
-        
+
         if (host.getXmlBase()!=null) {
             configBase = returnCanonicalPath(host.getXmlBase());
         } else {
@@ -472,16 +477,16 @@ public class HostConfig
         deployWARs(appBase, filteredAppPaths);
         // Deploy expanded folders
         deployDirectories(appBase, filteredAppPaths);
-        
+
     }
 
 
     /**
      * Filter the list of application file paths to remove those that match
      * the regular expression defined by {@link Host#getDeployIgnore()}.
-     *  
+     *
      * @param unfilteredAppPaths    The list of application paths to filtert
-     * 
+     *
      * @return  The filtered list of application paths
      */
     protected String[] filterAppPaths(String[] unfilteredAppPaths) {
@@ -520,7 +525,7 @@ public class HostConfig
         File configBase = configBase();
         ContextName cn = new ContextName(name);
         String baseName = cn.getBaseName();
-        
+
         if (deploymentExists(baseName)) {
             return;
         }
@@ -551,7 +556,7 @@ public class HostConfig
 
         if (files == null)
             return;
-        
+
         ExecutorService es = host.getStartStopExecutor();
         List<Future<?>> results = new ArrayList<Future<?>>();
 
@@ -563,7 +568,7 @@ public class HostConfig
 
                 if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
                     continue;
-                
+
                 results.add(
                         es.submit(new DeployDescriptor(this, cn, contextXml)));
             }
@@ -585,7 +590,7 @@ public class HostConfig
      * @param contextXml
      */
     protected void deployDescriptor(ContextName cn, File contextXml) {
-        
+
         DeployedApplication deployedApp = new DeployedApplication(cn.getName());
 
         // Assume this is a configuration descriptor and deploy it
@@ -598,10 +603,12 @@ public class HostConfig
         boolean isExternalWar = false;
         boolean isExternal = false;
         File expandedDocBase = null;
+        FileInputStream fis = null;
         try {
+            fis = new FileInputStream(contextXml);
             synchronized (digester) {
                 try {
-                    context = (Context) digester.parse(contextXml);
+                    context = (Context) digester.parse(fis);
                 } catch (Exception e) {
                     log.error(sm.getString(
                             "hostConfig.deployDescriptor.error",
@@ -653,6 +660,13 @@ public class HostConfig
             log.error(sm.getString("hostConfig.deployDescriptor.error",
                                    contextXml.getAbsolutePath()), t);
         } finally {
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
             // Get paths for WAR and expanded WAR in appBase
 
             // default to appBase dir + name
@@ -686,7 +700,7 @@ public class HostConfig
                 if (expandedDocBase.exists()) {
                     deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(),
                             Long.valueOf(expandedDocBase.lastModified()));
-                    addWatchedResources(deployedApp, 
+                    addWatchedResources(deployedApp,
                             expandedDocBase.getAbsolutePath(), context);
                 } else {
                     addWatchedResources(deployedApp, null, context);
@@ -713,15 +727,15 @@ public class HostConfig
      * Deploy WAR files.
      */
     protected void deployWARs(File appBase, String[] files) {
-        
+
         if (files == null)
             return;
-        
+
         ExecutorService es = host.getStartStopExecutor();
         List<Future<?>> results = new ArrayList<Future<?>>();
 
         for (int i = 0; i < files.length; i++) {
-            
+
             if (files[i].equalsIgnoreCase("META-INF"))
                 continue;
             if (files[i].equalsIgnoreCase("WEB-INF"))
@@ -729,9 +743,9 @@ public class HostConfig
             File war = new File(appBase, files[i]);
             if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile()
                     && !invalidWars.contains(files[i]) ) {
-                
+
                 ContextName cn = new ContextName(files[i]);
-                
+
                 // Check for WARs with /../ /./ or similar sequences in the name
                 if (!validateContextPath(appBase, cn.getBaseName())) {
                     log.error(sm.getString(
@@ -742,7 +756,7 @@ public class HostConfig
 
                 if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
                     continue;
-                
+
                 results.add(es.submit(new DeployWar(this, cn, war)));
             }
         }
@@ -761,10 +775,10 @@ public class HostConfig
     private boolean validateContextPath(File appBase, String contextPath) {
         // More complicated than the ideal as the canonical path may or may
         // not end with File.separator for a directory
-        
+
         StringBuilder docBase;
         String canonicalDocBase = null;
-        
+
         try {
             String canonicalAppBase = appBase.getCanonicalPath();
             docBase = new StringBuilder(canonicalAppBase);
@@ -776,10 +790,10 @@ public class HostConfig
             }
             // At this point docBase should be canonical but will not end
             // with File.separator
-            
+
             canonicalDocBase =
                 (new File(docBase.toString())).getCanonicalPath();
-    
+
             // If the canonicalDocBase ends with File.separator, add one to
             // docBase before they are compared
             if (canonicalDocBase.endsWith(File.separator)) {
@@ -788,9 +802,9 @@ public class HostConfig
         } catch (IOException ioe) {
             return false;
         }
-        
+
         // Compare the two. If they are not the same, the contextPath must
-        // have /../ like sequences in it 
+        // have /../ like sequences in it
         return canonicalDocBase.equals(docBase.toString());
     }
 
@@ -799,7 +813,7 @@ public class HostConfig
      * @param war
      */
     protected void deployWAR(ContextName cn, File war) {
-        
+
         // Checking for a nested /META-INF/context.xml
         JarFile jar = null;
         JarEntry entry = null;
@@ -814,7 +828,7 @@ public class HostConfig
                     cn.getBaseName() + "/META-INF/context.xml");
         }
         boolean xmlInWar = false;
-        
+
         if (deployXML && !xml.exists()) {
             try {
                 jar = new JarFile(war);
@@ -824,7 +838,7 @@ public class HostConfig
                 }
                 if ((copyXML || unpackWARs) && xmlInWar) {
                     istream = jar.getInputStream(entry);
-                    
+
                     fos = new FileOutputStream(xml);
                     ostream = new BufferedOutputStream(fos, 1024);
                     byte buffer[] = new byte[1024];
@@ -875,11 +889,11 @@ public class HostConfig
                 }
             }
         }
-        
+
         DeployedApplication deployedApp = new DeployedApplication(cn.getName());
-        
+
         // Deploy the application in this WAR file
-        if(log.isInfoEnabled()) 
+        if(log.isInfoEnabled())
             log.info(sm.getString("hostConfig.deployWar",
                     war.getAbsolutePath()));
 
@@ -985,7 +999,7 @@ public class HostConfig
             // the end so they don't interfere with the deletion process
             addGlobalRedeployResources(deployedApp);
         }
-        
+
         deployed.put(cn.getName(), deployedApp);
     }
 
@@ -997,7 +1011,7 @@ public class HostConfig
 
         if (files == null)
             return;
-        
+
         ExecutorService es = host.getStartStopExecutor();
         List<Future<?>> results = new ArrayList<Future<?>>();
 
@@ -1028,17 +1042,17 @@ public class HostConfig
         }
     }
 
-    
+
     /**
      * @param cn
      * @param dir
      */
     protected void deployDirectory(ContextName cn, File dir) {
-        
+
         DeployedApplication deployedApp = new DeployedApplication(cn.getName());
 
         // Deploy the application in this directory
-        if( log.isInfoEnabled() ) 
+        if( log.isInfoEnabled() )
             log.info(sm.getString("hostConfig.deployDir",
                     dir.getAbsolutePath()));
 
@@ -1125,17 +1139,17 @@ public class HostConfig
         deployed.put(cn.getName(), deployedApp);
     }
 
-    
+
     /**
      * Check if a webapp is already deployed in this host.
-     * 
+     *
      * @param contextName of the context which will be checked
      */
     protected boolean deploymentExists(String contextName) {
         return (deployed.containsKey(contextName) ||
                 (host.findChild(contextName) != null));
     }
-    
+
 
     /**
      * Add watched resources to the specified Context.
@@ -1171,11 +1185,11 @@ public class HostConfig
             if(log.isDebugEnabled())
                 log.debug("Watching WatchedResource '" +
                         resource.getAbsolutePath() + "'");
-            app.reloadResources.put(resource.getAbsolutePath(), 
+            app.reloadResources.put(resource.getAbsolutePath(),
                     Long.valueOf(resource.lastModified()));
         }
     }
-    
+
 
     protected void addGlobalRedeployResources(DeployedApplication app) {
         // Redeploy resources processing is hard-coded to never delete this file
@@ -1213,43 +1227,7 @@ public class HostConfig
                 if ((!resource.isDirectory()) &&
                         resource.lastModified() > lastModified) {
                     // Undeploy application
-                    if (log.isInfoEnabled())
-                        log.info(sm.getString("hostConfig.undeploy", app.name));
-                    Container context = host.findChild(app.name);
-                    try {
-                        host.removeChild(context);
-                    } catch (Throwable t) {
-                        ExceptionUtils.handleThrowable(t);
-                        log.warn(sm.getString
-                                 ("hostConfig.context.remove", app.name), t);
-                    }
-                    // Delete other redeploy resources
-                    for (int j = i + 1; j < resources.length; j++) {
-                        try {
-                            File current = new File(resources[j]);
-                            current = current.getCanonicalFile();
-                            // Never delete per host context.xml defaults
-                            if (Constants.HostContextXml.equals(
-                                    current.getName())) {
-                                continue;
-                            }
-                            // Only delete resources in the appBase or the
-                            // host's configBase
-                            if ((current.getAbsolutePath().startsWith(
-                                    appBase().getAbsolutePath() +
-                                    File.separator))
-                                    || (current.getAbsolutePath().startsWith(
-                                            configBase().getAbsolutePath()))) {
-                                if (log.isDebugEnabled())
-                                    log.debug("Delete " + current);
-                                ExpandWar.delete(current);
-                            }
-                        } catch (IOException e) {
-                            log.warn(sm.getString
-                                    ("hostConfig.canonicalizing", app.name), e);
-                        }
-                    }
-                    deployed.remove(app.name);
+                    deleteRedeployResources(app, resources, i, false);
                     return;
                 }
             } else {
@@ -1270,71 +1248,7 @@ public class HostConfig
                     continue;
                 }
                 // Undeploy application
-                if (log.isInfoEnabled())
-                    log.info(sm.getString("hostConfig.undeploy", app.name));
-                Container context = host.findChild(app.name);
-                try {
-                    host.removeChild(context);
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    log.warn(sm.getString
-                             ("hostConfig.context.remove", app.name), t);
-                }
-                // Delete all redeploy resources
-                for (int j = i + 1; j < resources.length; j++) {
-                    try {
-                        File current = new File(resources[j]);
-                        current = current.getCanonicalFile();
-                        // Never delete per host context.xml defaults
-                        if (Constants.HostContextXml.equals(
-                                current.getName())) {
-                            continue;
-                        }
-                        // Only delete resources in the appBase or the host's
-                        // configBase
-                        if ((current.getAbsolutePath().startsWith(
-                                appBase().getAbsolutePath() + File.separator))
-                            || (current.getAbsolutePath().startsWith(
-                                    configBase().getAbsolutePath()))) {
-                            if (log.isDebugEnabled())
-                                log.debug("Delete " + current);
-                            ExpandWar.delete(current);
-                        }
-                    } catch (IOException e) {
-                        log.warn(sm.getString
-                                ("hostConfig.canonicalizing", app.name), e);
-                    }
-                }
-                // Delete reload resources as well (to remove any remaining .xml
-                // descriptor)
-                String[] resources2 =
-                    app.reloadResources.keySet().toArray(new String[0]);
-                for (int j = 0; j < resources2.length; j++) {
-                    try {
-                        File current = new File(resources2[j]);
-                        current = current.getCanonicalFile();
-                        // Never delete per host context.xml defaults
-                        if (Constants.HostContextXml.equals(
-                                current.getName())) {
-                            continue;
-                        }
-                        // Only delete resources in the appBase or the host's
-                        // configBase
-                        if ((current.getAbsolutePath().startsWith(
-                                appBase().getAbsolutePath() + File.separator))
-                            || ((current.getAbsolutePath().startsWith(
-                                    configBase().getAbsolutePath())
-                                 && (current.getAbsolutePath().endsWith(".xml"))))) {
-                            if (log.isDebugEnabled())
-                                log.debug("Delete " + current);
-                            ExpandWar.delete(current);
-                        }
-                    } catch (IOException e) {
-                        log.warn(sm.getString
-                                ("hostConfig.canonicalizing", app.name), e);
-                    }
-                }
-                deployed.remove(app.name);
+                deleteRedeployResources(app, resources, i, true);
                 return;
             }
         }
@@ -1346,7 +1260,7 @@ public class HostConfig
                         "] reload resource " + resource);
             long lastModified =
                 app.reloadResources.get(resources[i]).longValue();
-            if ((!resource.exists() && lastModified != 0L) 
+            if ((!resource.exists() && lastModified != 0L)
                 || (resource.lastModified() != lastModified)) {
                 // Reload application
                 if(log.isInfoEnabled())
@@ -1373,8 +1287,83 @@ public class HostConfig
             }
         }
     }
-    
-    
+
+
+    private void deleteRedeployResources(DeployedApplication app,
+            String[] resources, int i, boolean deleteReloadResources) {
+
+        // Delete redeploy resources
+        if (log.isInfoEnabled())
+            log.info(sm.getString("hostConfig.undeploy", app.name));
+        Container context = host.findChild(app.name);
+        try {
+            host.removeChild(context);
+        } catch (Throwable t) {
+            ExceptionUtils.handleThrowable(t);
+            log.warn(sm.getString
+                     ("hostConfig.context.remove", app.name), t);
+        }
+        // Delete other redeploy resources
+        for (int j = i + 1; j < resources.length; j++) {
+            try {
+                File current = new File(resources[j]);
+                current = current.getCanonicalFile();
+                // Never delete per host context.xml defaults
+                if (Constants.HostContextXml.equals(
+                        current.getName())) {
+                    continue;
+                }
+                // Only delete resources in the appBase or the
+                // host's configBase
+                if ((current.getAbsolutePath().startsWith(
+                        appBase().getAbsolutePath() +
+                        File.separator))
+                        || (current.getAbsolutePath().startsWith(
+                                configBase().getAbsolutePath()))) {
+                    if (log.isDebugEnabled())
+                        log.debug("Delete " + current);
+                    ExpandWar.delete(current);
+                }
+            } catch (IOException e) {
+                log.warn(sm.getString
+                        ("hostConfig.canonicalizing", app.name), e);
+            }
+        }
+
+        // Delete reload resources (to remove any remaining .xml descriptor)
+        if (deleteReloadResources) {
+            String[] resources2 =
+                    app.reloadResources.keySet().toArray(new String[0]);
+            for (int j = 0; j < resources2.length; j++) {
+                try {
+                    File current = new File(resources2[j]);
+                    current = current.getCanonicalFile();
+                    // Never delete per host context.xml defaults
+                    if (Constants.HostContextXml.equals(
+                            current.getName())) {
+                        continue;
+                    }
+                    // Only delete resources in the appBase or the host's
+                    // configBase
+                    if ((current.getAbsolutePath().startsWith(
+                            appBase().getAbsolutePath() + File.separator))
+                        || ((current.getAbsolutePath().startsWith(
+                                configBase().getAbsolutePath())
+                             && (current.getAbsolutePath().endsWith(".xml"))))) {
+                        if (log.isDebugEnabled())
+                            log.debug("Delete " + current);
+                        ExpandWar.delete(current);
+                    }
+                } catch (IOException e) {
+                    log.warn(sm.getString
+                            ("hostConfig.canonicalizing", app.name), e);
+                }
+            }
+
+        }
+        deployed.remove(app.name);
+    }
+
     /**
      * Process a "start" event for this Host.
      */
@@ -1392,7 +1381,7 @@ public class HostConfig
         } catch (Exception e) {
             log.error(sm.getString("hostConfig.jmx.register", oname), e);
         }
-        
+
         if (host.getCreateDirs()) {
             File[] dirs = new File[] {appBase(),configBase()};
             for (int i=0; i<dirs.length; i++) {
@@ -1411,7 +1400,7 @@ public class HostConfig
 
         if (host.getDeployOnStartup())
             deployApps();
-        
+
     }
 
 
@@ -1444,19 +1433,24 @@ public class HostConfig
 
         if (host.getAutoDeploy()) {
             // Check for resources modification to trigger redeployment
-            DeployedApplication[] apps = 
+            DeployedApplication[] apps =
                 deployed.values().toArray(new DeployedApplication[0]);
             for (int i = 0; i < apps.length; i++) {
                 if (!isServiced(apps[i].name))
                     checkResources(apps[i]);
             }
+
+            // Check for old versions of applications that can now be undeployed
+            if (host.getUndeployOldVersions()) {
+                checkUndeploy();
+            }
+
             // Hotdeploy applications
             deployApps();
         }
-
     }
 
-    
+
     /**
      * Check status of a specific webapp, for use with stuff like management webapps.
      */
@@ -1470,18 +1464,79 @@ public class HostConfig
     }
 
     /**
+     * Check for old versions of applications using parallel deployment that are
+     * now unused (have no active sessions) and undeploy any that are found.
+     */
+    public synchronized void checkUndeploy() {
+        // Need ordered set of names
+        SortedSet<String> sortedAppNames = new TreeSet<String>();
+        sortedAppNames.addAll(deployed.keySet());
+
+        if (sortedAppNames.size() < 2) {
+            return;
+        }
+        Iterator<String> iter = sortedAppNames.iterator();
+
+        ContextName previous = new ContextName(iter.next());
+        do {
+            ContextName current = new ContextName(iter.next());
+
+            if (current.getPath().equals(previous.getPath())) {
+                // Current and previous are same path - current will always
+                // be a later version
+                Context previousContext =
+                        (Context) host.findChild(previous.getName());
+                Context currentContext =
+                        (Context) host.findChild(previous.getName());
+                if (previousContext != null && currentContext != null &&
+                        currentContext.getState().isAvailable() &&
+                        !isServiced(previous.getName())) {
+                    Manager manager = previousContext.getManager();
+                    if (manager != null) {
+                        int sessionCount;
+                        if (manager instanceof DistributedManager) {
+                            sessionCount = ((DistributedManager)
+                                    manager).getActiveSessionsFull();
+                        } else {
+                            sessionCount = manager.getActiveSessions();
+                        }
+                        if (sessionCount == 0) {
+                            if (log.isInfoEnabled()) {
+                                log.info(sm.getString(
+                                        "hostConfig.undeployVersion",
+                                        previous.getName()));
+                            }
+                            DeployedApplication app =
+                                    deployed.get(previous.getName());
+                            String[] resources =
+                                    app.redeployResources.keySet().toArray(
+                                            new String[0]);
+                            // Version is unused - undeploy it completely
+                            // The -1 is a 'trick' to ensure all redeploy
+                            // resources are removed
+                            deleteRedeployResources(app, resources, -1,
+                                    true);
+                        }
+                    }
+                }
+            }
+            previous = current;
+        } while (iter.hasNext());
+    }
+
+    /**
      * Add a new Context to be managed by us.
      * Entry point for the admin webapp, and other JMX Context controllers.
      */
-    public void manageApp(Context context)  {    
+    public void manageApp(Context context)  {
 
         String contextName = context.getName();
-        
+
         if (deployed.containsKey(contextName))
             return;
 
         DeployedApplication deployedApp = new DeployedApplication(contextName);
-        
+
         // Add the associated docBase to the redeployed list if it's a WAR
         boolean isWar = false;
         if (context.getDocBase() != null) {
@@ -1524,22 +1579,22 @@ public class HostConfig
 
 
     /**
-     * This class represents the state of a deployed application, as well as 
+     * This class represents the state of a deployed application, as well as
      * the monitored resources.
      */
     protected static class DeployedApplication {
         public DeployedApplication(String name) {
             this.name = name;
         }
-        
+
         /**
-         * Application context path. The assertion is that 
+         * Application context path. The assertion is that
          * (host.getChild(name) != null).
          */
         public String name;
-        
+
         /**
-         * Any modification of the specified (static) resources will cause a 
+         * Any modification of the specified (static) resources will cause a
          * redeployment of the application. If any of the specified resources is
          * removed, the application will be undeployed. Typically, this will
          * contain resources like the context.xml file, a compressed WAR path.
@@ -1549,7 +1604,7 @@ public class HostConfig
             new LinkedHashMap<String, Long>();
 
         /**
-         * Any modification of the specified (static) resources will cause a 
+         * Any modification of the specified (static) resources will cause a
          * reload of the application. This will typically contain resources
          * such as the web.xml of a webapp, but can be configured to contain
          * additional descriptors.
diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties
index c9d914a..4c6f701 100644
--- a/java/org/apache/catalina/startup/LocalStrings.properties
+++ b/java/org/apache/catalina/startup/LocalStrings.properties
@@ -111,6 +111,7 @@ hostConfig.start=HostConfig: Processing START
 hostConfig.stop=HostConfig: Processing STOP
 hostConfig.undeploy=Undeploying context [{0}]
 hostConfig.undeploy.error=Error undeploying web application at context path {0}
+hostConfig.undeployVersion=Undeploying old version of context [{0}] which has no active session
 tldConfig.addListeners=Adding {0} listeners from TLD files
 tldConfig.cce=Lifecycle event data object {0} is not a Context
 tldConfig.dirFail=Failed to process directory [{0}] for TLD files
diff --git a/java/org/apache/catalina/startup/RealmRuleSet.java b/java/org/apache/catalina/startup/RealmRuleSet.java
index ad1319d..42d4294 100644
--- a/java/org/apache/catalina/startup/RealmRuleSet.java
+++ b/java/org/apache/catalina/startup/RealmRuleSet.java
@@ -28,12 +28,16 @@ import org.apache.tomcat.util.digester.RuleSetBase;
  * element.  This <code>RuleSet</code> supports Realms such as the
  * <code>CombinedRealm</code> that used nested Realms.</p>
  *
- * @version $Id: RealmRuleSet.java 939305 2010-04-29 13:43:39Z kkolinko $
+ * @version $Id: RealmRuleSet.java 1408741 2012-11-13 14:20:16Z markt $
  */
 
 public class RealmRuleSet extends RuleSetBase {
 
 
+    private static final int MAX_NESTED_REALM_LEVELS = Integer.getInteger(
+            "org.apache.catalina.startup.RealmRuleSet.MAX_NESTED_REALM_LEVELS",
+            3).intValue();
+
     // ----------------------------------------------------- Instance Variables
 
 
@@ -88,23 +92,28 @@ public class RealmRuleSet extends RuleSetBase {
     @Override
     public void addRuleInstances(Digester digester) {
 
-        digester.addObjectCreate(prefix + "Realm",
-                                 null, // MUST be specified in the element,
-                                 "className");
-        digester.addSetProperties(prefix + "Realm");
-        digester.addSetNext(prefix + "Realm",
-                            "setRealm",
-                            "org.apache.catalina.Realm");
-
-        digester.addObjectCreate(prefix + "Realm/Realm",
-                                 null, // MUST be specified in the element
-                                 "className");
-        digester.addSetProperties(prefix + "Realm/Realm");
-        digester.addSetNext(prefix + "Realm/Realm",
-                            "addRealm",
-                            "org.apache.catalina.Realm");
-
+        String pattern = prefix;
+
+        for (int i = 0; i < MAX_NESTED_REALM_LEVELS; i++) {
+
+            if (i > 0) {
+                pattern += "/";
+            }
+            pattern += "Realm";
+
+            digester.addObjectCreate(pattern,
+                                     null, // MUST be specified in the element,
+                                     "className");
+            digester.addSetProperties(pattern);
+            if (i == 0) {
+                digester.addSetNext(pattern,
+                                    "setRealm",
+                                    "org.apache.catalina.Realm");
+            } else {
+                digester.addSetNext(pattern,
+                                    "addRealm",
+                                    "org.apache.catalina.Realm");
+            }
+        }
     }
-
-
 }
diff --git a/java/org/apache/catalina/startup/TldConfig.java b/java/org/apache/catalina/startup/TldConfig.java
index e7756f0..f3a3b61 100644
--- a/java/org/apache/catalina/startup/TldConfig.java
+++ b/java/org/apache/catalina/startup/TldConfig.java
@@ -119,6 +119,47 @@ public final class TldConfig  implements LifecycleListener {
     }
 
 
+    static {
+        // Set the default list of JARs to skip for TLDs
+        StringBuilder jarList = new StringBuilder(System.getProperty(
+                Constants.DEFAULT_JARS_TO_SKIP, ""));
+
+        String tldJars = System.getProperty(Constants.TLD_JARS_TO_SKIP, "");
+        if (tldJars.length() > 0) {
+            if (jarList.length() > 0) {
+                jarList.append(',');
+            }
+            jarList.append(tldJars);
+        }
+
+        if (jarList.length() > 0) {
+            setNoTldJars(jarList.toString());
+        }
+    }
+
+    /**
+     * Sets the list of JARs that are known not to contain any TLDs.
+     *
+     * @param jarNames List of comma-separated names of JAR files that are
+     * known not to contain any TLDs.
+     */
+    public static synchronized void setNoTldJars(String jarNames) {
+        if (jarNames == null) {
+            noTldJars = null;
+        } else {
+            if (noTldJars == null) {
+                noTldJars = new HashSet<String>();
+            } else {
+                noTldJars.clear();
+            }
+            StringTokenizer tokenizer = new StringTokenizer(jarNames, ",");
+            while (tokenizer.hasMoreElements()) {
+                noTldJars.add(tokenizer.nextToken());
+            }
+        }
+    }
+
+
     // ----------------------------------------------------- Instance Variables
 
     /**
@@ -169,31 +210,17 @@ public final class TldConfig  implements LifecycleListener {
     }
 
     /**
-     * Sets the list of JARs that are known not to contain any TLDs.
-     *
-     * @param jarNames List of comma-separated names of JAR files that are 
-     * known not to contain any TLDs.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
-    public static void setNoTldJars(String jarNames) {
-        if (jarNames == null) {
-            noTldJars = null;
-        } else {
-            if (noTldJars == null) {
-                noTldJars = new HashSet<String>();
-            } else {
-                noTldJars.clear();
-            }
-            StringTokenizer tokenizer = new StringTokenizer(jarNames, ",");
-            while (tokenizer.hasMoreElements()) {
-                noTldJars.add(tokenizer.nextToken());
-            }
-        }
-    }
-
+    @Deprecated
     public Context getContext() {
         return context;
     }
 
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public void setContext(Context context) {
         this.context = context;
     }
diff --git a/java/org/apache/catalina/startup/Tomcat.java b/java/org/apache/catalina/startup/Tomcat.java
index ff66ab2..74b73d3 100644
--- a/java/org/apache/catalina/startup/Tomcat.java
+++ b/java/org/apache/catalina/startup/Tomcat.java
@@ -746,14 +746,16 @@ public class Tomcat {
         Wrapper servlet = addServlet(
                 ctx, "default", "org.apache.catalina.servlets.DefaultServlet");
         servlet.setLoadOnStartup(1);
+        servlet.setOverridable(true);
 
         // JSP servlet (by class name - to avoid loading all deps)
         servlet = addServlet(
                 ctx, "jsp", "org.apache.jasper.servlet.JspServlet");
         servlet.addInitParameter("fork", "false");
         servlet.setLoadOnStartup(3);
-        
-        // Servlet mappings 
+        servlet.setOverridable(true);
+
+        // Servlet mappings
         ctx.addServletMapping("/", "default");
         ctx.addServletMapping("*.jsp", "jsp");
         ctx.addServletMapping("*.jspx", "jsp");
diff --git a/java/org/apache/catalina/startup/WebRuleSet.java b/java/org/apache/catalina/startup/WebRuleSet.java
index f121926..4b645e4 100644
--- a/java/org/apache/catalina/startup/WebRuleSet.java
+++ b/java/org/apache/catalina/startup/WebRuleSet.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 
 import org.apache.catalina.deploy.ContextHandler;
 import org.apache.catalina.deploy.ContextService;
+import org.apache.catalina.deploy.ResourceBase;
 import org.apache.catalina.deploy.SecurityConstraint;
 import org.apache.catalina.deploy.ServletDef;
 import org.apache.catalina.deploy.WebXml;
@@ -43,7 +44,7 @@ import org.xml.sax.Attributes;
  * deployment descriptor (<code>/WEB-INF/web.xml</code>) resource.</p>
  *
  * @author Craig R. McClanahan
- * @version $Id: WebRuleSet.java 1345031 2012-06-01 09:43:15Z markt $
+ * @version $Id: WebRuleSet.java 1373621 2012-08-15 20:37:06Z markt $
  */
 
 public class WebRuleSet extends RuleSetBase {
@@ -302,7 +303,7 @@ public class WebRuleSet extends RuleSetBase {
         digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/trim-directive-whitespaces",
                                "setTrimWhitespace", 0);
         digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/url-pattern",
-                               "setUrlPattern", 0);
+                               "addUrlPattern", 0);
         digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/default-content-type",
                                "setDefaultContentType", 0);
         digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/buffer",
@@ -493,6 +494,8 @@ public class WebRuleSet extends RuleSetBase {
                                "setLocal", 0);
         digester.addCallMethod(fullPrefix + "/ejb-local-ref/local-home",
                                "setHome", 0);
+        digester.addRule(fullPrefix + "/ejb-local-ref/mapped-name",
+                         new MappedNameRule());
         configureInjectionRules(digester, "web-app/ejb-local-ref/");
 
         //ejb-ref
@@ -513,6 +516,8 @@ public class WebRuleSet extends RuleSetBase {
                                "setHome", 0);
         digester.addCallMethod(fullPrefix + "/ejb-ref/remote",
                                "setRemote", 0);
+        digester.addRule(fullPrefix + "/ejb-ref/mapped-name",
+                         new MappedNameRule());
         configureInjectionRules(digester, "web-app/ejb-ref/");
 
         //env-entry
@@ -529,6 +534,8 @@ public class WebRuleSet extends RuleSetBase {
                                "setType", 0);
         digester.addCallMethod(fullPrefix + "/env-entry/env-entry-value",
                                "setValue", 0);
+        digester.addRule(fullPrefix + "/env-entry/mapped-name",
+                         new MappedNameRule());
         configureInjectionRules(digester, "web-app/env-entry/");
 
         //resource-env-ref
@@ -541,6 +548,8 @@ public class WebRuleSet extends RuleSetBase {
                 "setName", 0);
         digester.addCallMethod(fullPrefix + "/resource-env-ref/resource-env-ref-type",
                 "setType", 0);
+        digester.addRule(fullPrefix + "/resource-env-ref/mapped-name",
+                         new MappedNameRule());
         configureInjectionRules(digester, "web-app/resource-env-ref/");
 
         //message-destination
@@ -559,6 +568,8 @@ public class WebRuleSet extends RuleSetBase {
                                "setSmallIcon", 0);
         digester.addCallMethod(fullPrefix + "/message-destination/message-destination-name",
                                "setName", 0);
+        digester.addRule(fullPrefix + "/message-destination/mapped-name",
+                         new MappedNameRule());
 
         //message-destination-ref
         digester.addObjectCreate(fullPrefix + "/message-destination-ref",
@@ -576,7 +587,8 @@ public class WebRuleSet extends RuleSetBase {
                                "setType", 0);
         digester.addCallMethod(fullPrefix + "/message-destination-ref/message-destination-usage",
                                "setUsage", 0);
-
+        digester.addRule(fullPrefix + "/message-destination-ref/mapped-name",
+                         new MappedNameRule());
         configureInjectionRules(digester, "web-app/message-destination-ref/");
 
         //resource-ref
@@ -595,6 +607,8 @@ public class WebRuleSet extends RuleSetBase {
                                "setScope", 0);
         digester.addCallMethod(fullPrefix + "/resource-ref/res-type",
                                "setType", 0);
+        digester.addRule(fullPrefix + "/resource-ref/mapped-name",
+                         new MappedNameRule());
         configureInjectionRules(digester, "web-app/resource-ref/");
 
         //service-ref
@@ -652,9 +666,9 @@ public class WebRuleSet extends RuleSetBase {
                                "addSoapRole", 0);
         digester.addCallMethod(fullPrefix + "/service-ref/handler/port-name",
                                "addPortName", 0);
+        digester.addRule(fullPrefix + "/service-ref/mapped-name",
+                         new MappedNameRule());
         configureInjectionRules(digester, "web-app/service-ref/");
-
-
     }
 
     protected void configureInjectionRules(Digester digester, String base) {
@@ -1246,6 +1260,31 @@ final class TaglibLocationRule extends Rule {
                     "taglib definition not consistent with specification version");
         }
     }
+}
 
-    
+/**
+ * A Rule that sets mapped name on the ResourceBase.
+ */
+final class MappedNameRule extends Rule {
+
+    public MappedNameRule() {
+        // NO-OP
+    }
+
+    /**
+     * Process the body text of this element.
+     *
+     * @param namespace the namespace URI of the matching element, or an
+     *   empty string if the parser is not namespace aware or the element has
+     *   no namespace
+     * @param name the local name if the parser is namespace aware, or just
+     *   the element name otherwise
+     * @param text The body text of this element
+     */
+    @Override
+    public void body(String namespace, String name, String text)
+            throws Exception {
+        ResourceBase resourceBase = (ResourceBase) digester.peek();
+        resourceBase.setProperty("mappedName", text.trim());
+    }
 }
\ No newline at end of file
diff --git a/java/org/apache/catalina/startup/mbeans-descriptors.xml b/java/org/apache/catalina/startup/mbeans-descriptors.xml
index cffff34..3a2cb5c 100644
--- a/java/org/apache/catalina/startup/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/startup/mbeans-descriptors.xml
@@ -109,6 +109,12 @@
                  type="java.lang.String"/>
     </operation>
     
+    <operation name="checkUndeploy"
+               description="Undeploy any old versions of applications deployed using parallel deployment that have no active sessions"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+
     <operation name="getDeploymentTime"
                description="Get the instant where an application was deployed"
                impact="ACTION"
diff --git a/java/org/apache/catalina/tribes/Constants.java b/java/org/apache/catalina/tribes/Constants.java
index 9333759..eb42a11 100644
--- a/java/org/apache/catalina/tribes/Constants.java
+++ b/java/org/apache/catalina/tribes/Constants.java
@@ -24,9 +24,11 @@ package org.apache.catalina.tribes;
  *
  * @author Bip Thelin
  * @author Filip Hanik
- * @version $Id: Constants.java 939305 2010-04-29 13:43:39Z kkolinko $
+ * @version $Id: Constants.java 1370475 2012-08-07 19:54:29Z markt $
+ *
+ * @deprecated  Unused - will be removed in 8.0.x
  */
-
+ at Deprecated
 public final class Constants {
     public static final String Package = "org.apache.catalina.tribes";
 }
diff --git a/java/org/apache/catalina/tribes/ErrorHandler.java b/java/org/apache/catalina/tribes/ErrorHandler.java
index db5de4f..4508b33 100644
--- a/java/org/apache/catalina/tribes/ErrorHandler.java
+++ b/java/org/apache/catalina/tribes/ErrorHandler.java
@@ -32,14 +32,14 @@ public interface ErrorHandler {
      * Invoked if the message is dispatched asynch, and an error occurs
      * @param x ChannelException - the error that happened
      * @param id - the unique id for the message
-     * @see Channel#send(Member[], Serializable, int, ErrorHandler)
+     * @see Channel#send(Member[], java.io.Serializable, int, ErrorHandler)
      */
     public void handleError(ChannelException x, UniqueId id);
     
     /**
      * Invoked when the message has been sent successfully.
      * @param id - the unique id for the message
-     * @see Channel#send(Member[], Serializable, int, ErrorHandler)
+     * @see Channel#send(Member[], java.io.Serializable, int, ErrorHandler)
      */
     public void handleCompletion(UniqueId id);
     
diff --git a/java/org/apache/catalina/tribes/group/RpcChannel.java b/java/org/apache/catalina/tribes/group/RpcChannel.java
index 39c4c04..b2194cd 100644
--- a/java/org/apache/catalina/tribes/group/RpcChannel.java
+++ b/java/org/apache/catalina/tribes/group/RpcChannel.java
@@ -88,7 +88,7 @@ public class RpcChannel implements ChannelListener{
             channelOptions & ~Channel.SEND_OPTIONS_SYNCHRONIZED_ACK;
         
         RpcCollectorKey key = new RpcCollectorKey(UUIDGenerator.randomUUID(false));
-        RpcCollector collector = new RpcCollector(key,rpcOptions,destination.length,timeout);
+        RpcCollector collector = new RpcCollector(key,rpcOptions,destination.length);
         try {
             synchronized (collector) {
                 if ( rpcOptions != NO_REPLY ) responseMap.put(key, collector);
@@ -230,15 +230,30 @@ public class RpcChannel implements ChannelListener{
         public RpcCollectorKey key;
         public int options;
         public int destcnt;
+        /**
+         * @deprecated  Unused - will be removed in Tomcat 8.0.x
+         */
+        @Deprecated
         public long timeout;
-        
-        public RpcCollector(RpcCollectorKey key, int options, int destcnt, long timeout) {
+
+        /**
+         * @deprecated  Use {@link
+         *              RpcChannel.RpcCollector#RpcChannel.RpcCollector(
+         *              RpcChannel.RpcCollectorKey, int, int)}
+         */
+        @Deprecated
+        public RpcCollector(RpcCollectorKey key, int options, int destcnt,
+                long timeout) {
             this.key = key;
             this.options = options;
             this.destcnt = destcnt;
             this.timeout = timeout;
         }
         
+        public RpcCollector(RpcCollectorKey key, int options, int destcnt) {
+            this(key, options, destcnt, 0);
+        }
+
         public void addResponse(Serializable message, Member sender){
             Response resp = new Response(sender,message);
             responses.add(resp);
@@ -300,6 +315,10 @@ public class RpcChannel implements ChannelListener{
         
     }
     
+    /**
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
+     */
+    @Deprecated
     protected static String bToS(byte[] data) {
         StringBuilder buf = new StringBuilder(4*16);
         buf.append("{");
@@ -309,4 +328,4 @@ public class RpcChannel implements ChannelListener{
     }
 
 
-}
\ No newline at end of file
+}
diff --git a/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java b/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
index 581de10..20b07c0 100644
--- a/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
+++ b/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
@@ -641,6 +641,10 @@ public class NonBlockingCoordinator extends ChannelInterceptorBase {
         protected MemberImpl[] view;
         protected UniqueId id;
         protected byte[] type;
+        /**
+         * @deprecated  Unused - will be removed in Tomcat 8.0.x
+         */
+        @Deprecated
         protected long timestamp = System.currentTimeMillis();
         
         public CoordinationMessage(XByteBuffer buf) {
diff --git a/java/org/apache/catalina/tribes/group/interceptors/TcpFailureDetector.java b/java/org/apache/catalina/tribes/group/interceptors/TcpFailureDetector.java
index b4951d7..1badc16 100644
--- a/java/org/apache/catalina/tribes/group/interceptors/TcpFailureDetector.java
+++ b/java/org/apache/catalina/tribes/group/interceptors/TcpFailureDetector.java
@@ -36,6 +36,7 @@ import org.apache.catalina.tribes.io.ChannelData;
 import org.apache.catalina.tribes.io.XByteBuffer;
 import org.apache.catalina.tribes.membership.MemberImpl;
 import org.apache.catalina.tribes.membership.Membership;
+import org.apache.catalina.tribes.membership.StaticMember;
 
 /**
  * <p>Title: A perfect failure detector </p>
@@ -157,6 +158,9 @@ public class TcpFailureDetector extends ChannelInterceptorBase {
                 //not correct, we need to maintain the map
                 membership.removeMember( (MemberImpl) member);
                 removeSuspects.remove(member);
+                if (member instanceof StaticMember) {
+                    addSuspects.put(member, Long.valueOf(System.currentTimeMillis()));
+                }
                 notify = true;
             } else {
                 //add the member as suspect
@@ -228,6 +232,9 @@ public class TcpFailureDetector extends ChannelInterceptorBase {
                 if (membership.getMember(members[i])!=null) {
                     membership.removeMember((MemberImpl)members[i]);
                     removeSuspects.remove(members[i]);
+                    if (members[i] instanceof StaticMember) {
+                        addSuspects.put(members[i], Long.valueOf(System.currentTimeMillis()));
+                    }
                     super.memberDisappeared(members[i]);
                 }
             } //end if
@@ -239,6 +246,10 @@ public class TcpFailureDetector extends ChannelInterceptorBase {
         //update all alive times
         Member[] members = super.getMembers();
         for (int i = 0; members != null && i < members.length; i++) {
+            if (addSuspects.containsKey(members[i]) && membership.getMember(members[i]) == null) {
+                // avoid temporary adding member.
+                continue;
+            }
             if (membership.memberAlive( (MemberImpl) members[i])) {
                 //we don't have this one in our membership, check to see if he/she is alive
                 if (memberAlive(members[i])) {
diff --git a/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java b/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java
index 26d6762..925d351 100644
--- a/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java
+++ b/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java
@@ -27,6 +27,7 @@ import org.apache.catalina.tribes.ChannelMessage;
 import org.apache.catalina.tribes.Member;
 import org.apache.catalina.tribes.group.ChannelInterceptorBase;
 import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.io.XByteBuffer;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 
@@ -64,7 +65,7 @@ public class TcpPingInterceptor extends ChannelInterceptorBase {
     public synchronized void start(int svc) throws ChannelException {
         super.start(svc);
         running = true;
-        if ( thread == null ) {
+        if ( thread == null && useThread) {
             thread = new PingThread();
             thread.setDaemon(true);
             thread.setName("TcpPingInterceptor.PingThread-"+cnt.addAndGet(1));
@@ -86,8 +87,10 @@ public class TcpPingInterceptor extends ChannelInterceptorBase {
     @Override
     public void stop(int svc) throws ChannelException {
         running = false;
-        if ( thread != null ) thread.interrupt();
-        thread = null;
+        if ( thread != null ) {
+            thread.interrupt();
+            thread = null;
+        }
         super.stop(svc);
     }
     
@@ -122,13 +125,17 @@ public class TcpPingInterceptor extends ChannelInterceptorBase {
     }
 
     protected void sendPing() {
-        if (failureDetector.get()!=null) {
-            //we have a reference to the failure detector
-            //piggy back on that dude
-            failureDetector.get().checkMembers(true);
-        }else {
-            if (staticOnly && staticMembers.get()!=null) {
-                sendPingMessage(staticMembers.get().getMembers());
+        TcpFailureDetector tcpFailureDetector =
+                failureDetector != null ? failureDetector.get() : null;
+        if (tcpFailureDetector != null) {
+            // We have a reference to the failure detector
+            // Piggy back on it
+            tcpFailureDetector.checkMembers(true);
+        } else {
+            StaticMembershipInterceptor smi =
+                    staticOnly && staticMembers != null ? staticMembers.get() : null;
+            if (smi != null) {
+                sendPingMessage(smi.getMembers());
             } else {
                 sendPingMessage(getMembers());
             }
@@ -141,6 +148,7 @@ public class TcpPingInterceptor extends ChannelInterceptorBase {
         data.setAddress(getLocalMember(false));
         data.setTimestamp(System.currentTimeMillis());
         data.setOptions(getOptionFlag());
+        data.setMessage(new XByteBuffer(TCP_PING_DATA, false));
         try {
             super.sendMessage(members, data, null);
         }catch (ChannelException x) {
diff --git a/java/org/apache/catalina/tribes/io/ReplicationStream.java b/java/org/apache/catalina/tribes/io/ReplicationStream.java
index a310034..562dd73 100644
--- a/java/org/apache/catalina/tribes/io/ReplicationStream.java
+++ b/java/org/apache/catalina/tribes/io/ReplicationStream.java
@@ -33,7 +33,7 @@ import java.lang.reflect.Proxy;
  * @author Craig R. McClanahan
  * @author Bip Thelin
  * @author Filip Hanik
- * @version $Id: ReplicationStream.java 939305 2010-04-29 13:43:39Z kkolinko $
+ * @version $Id: ReplicationStream.java 1366914 2012-07-29 19:32:20Z markt $
  */
 
 public final class ReplicationStream extends ObjectInputStream {
@@ -105,7 +105,12 @@ public final class ReplicationStream extends ObjectInputStream {
     protected Class<?> resolveProxyClass(String[] interfaces)
             throws IOException, ClassNotFoundException {
         
-        ClassLoader latestLoader = (classLoaders!=null && classLoaders.length==0)?null:classLoaders[0];
+        ClassLoader latestLoader;
+        if (classLoaders != null && classLoaders.length > 0) {
+            latestLoader = classLoaders[0];
+        } else {
+            latestLoader = null;
+        }
         ClassLoader nonPublicLoader = null;
         boolean hasNonPublicInterface = false;
 
diff --git a/java/org/apache/catalina/tribes/membership/MemberImpl.java b/java/org/apache/catalina/tribes/membership/MemberImpl.java
index ea005ec..f546e14 100644
--- a/java/org/apache/catalina/tribes/membership/MemberImpl.java
+++ b/java/org/apache/catalina/tribes/membership/MemberImpl.java
@@ -32,7 +32,7 @@ import org.apache.catalina.tribes.transport.SenderState;
  * Carries the host, and port of the this or other cluster nodes.
  *
  * @author Filip Hanik
- * @version $Id: MemberImpl.java 1142670 2011-07-04 13:59:53Z kkolinko $
+ * @version $Id: MemberImpl.java 1380072 2012-09-02 22:26:09Z markt $
  */
 public class MemberImpl implements Member, java.io.Externalizable {
 
@@ -41,11 +41,21 @@ public class MemberImpl implements Member, java.io.Externalizable {
      * default is false
      */
     public static final boolean DO_DNS_LOOKUPS = Boolean.parseBoolean(System.getProperty("org.apache.catalina.tribes.dns_lookups","false"));
+
     /**
-     * Public properties specific to this implementation
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     public static final transient String TCP_LISTEN_PORT = "tcpListenPort";
+    /**
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
+     */
+    @Deprecated
     public static final transient String TCP_LISTEN_HOST = "tcpListenHost";
+    /**
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
+     */
+    @Deprecated
     public static final transient String MEMBER_NAME = "memberName";
 
     public static final transient byte[] TRIBES_MBR_BEGIN = new byte[] {84, 82, 73, 66, 69, 83, 45, 66, 1, 0};
@@ -464,6 +474,10 @@ public class MemberImpl implements Member, java.io.Externalizable {
         }
     }
 
+    public int getMsgCount() {
+        return this.msgCount;
+    }
+
     /**
      * Contains information on how long this member has been online.
      * The result is the number of milli seconds this member has been
diff --git a/java/org/apache/catalina/tribes/membership/mbeans-descriptors.xml b/java/org/apache/catalina/tribes/membership/mbeans-descriptors.xml
index 3243734..debbc55 100644
--- a/java/org/apache/catalina/tribes/membership/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/tribes/membership/mbeans-descriptors.xml
@@ -97,4 +97,134 @@
       impact="ACTION"
       returnType="void"/>
   </mbean>
+  <mbean
+    name="MemberImpl"
+    description="Cluster member"
+    domain="Catalina"
+    group="Cluster"
+    type="org.apache.catalina.tribes.membership.MemberImpl">
+    <attribute
+      name="failing"
+      description="Has a problem been observed with this member (failing is worse than suspect)"
+      type="boolean"
+      is="true"
+      writeable="false"/>
+    <attribute
+      name="hostname"
+      description="The name of the host where this member is located"
+      type="String"
+      writeable="false"/>
+    <attribute
+      name="memberAliveTime"
+      description="The number of milliseconds since this member was created"
+      type="long"
+      writeable="false"/>
+    <attribute
+      name="msgCount"
+      description="The number of messages sent by this member"
+      type="int"
+      writeable="false"/>
+    <attribute
+      name="name"
+      description="The unique name of this member within the cluster"
+      type="String"
+      writeable="false"/>
+    <attribute
+      name="port"
+      description="The tcp port the member is listening on"
+      type="int"
+      writeable="false"/>
+    <attribute
+      name="ready"
+      description="Is this member ready to send messages"
+      type="boolean"
+      is="true"
+      writeable="false"/>
+    <attribute
+      name="securePort"
+      description="The tcp(SSL) port the member is listening on"
+      type="int"
+      writeable="false"/>
+    <attribute
+      name="serviceStartTime"
+      description="The time the member was started"
+      type="long"
+      writeable="false"/>
+    <attribute
+      name="suspect"
+      description="Has a potential problem been observed with this member (failing is worse than suspect)"
+      type="boolean"
+      is="true"
+      writeable="false"/>
+    <attribute
+      name="udpPort"
+      description="The upd port the member is listening on"
+      type="int"
+      writeable="false"/>
+  </mbean>
+  <mbean
+    name="StaticMember"
+    description="Cluster static member"
+    domain="Catalina"
+    group="Cluster"
+    type="org.apache.catalina.tribes.membership.StaticMember">
+    <attribute
+      name="failing"
+      description="Has a problem been observed with this member (failing is worse than suspect)"
+      type="boolean"
+      is="true"
+      writeable="false"/>
+    <attribute
+      name="hostname"
+      description="The name of the host where this member is located"
+      type="String"
+      writeable="false"/>
+    <attribute
+      name="memberAliveTime"
+      description="The number of milliseconds since this member was created"
+      type="long"
+      writeable="false"/>
+    <attribute
+      name="msgCount"
+      description="The number of messages sent by this member"
+      type="int"
+      writeable="false"/>
+    <attribute
+      name="name"
+      description="The unique name of this member within the cluster"
+      type="String"
+      writeable="false"/>
+    <attribute
+      name="port"
+      description="The tcp port the member is listening on"
+      type="int"
+      writeable="false"/>
+    <attribute
+      name="ready"
+      description="Is this member ready to send messages"
+      type="boolean"
+      is="true"
+      writeable="false"/>
+    <attribute
+      name="securePort"
+      description="The tcp(SSL) port the member is listening on"
+      type="int"
+      writeable="false"/>
+    <attribute
+      name="serviceStartTime"
+      description="The time the member was started"
+      type="long"
+      writeable="false"/>
+    <attribute
+      name="suspect"
+      description="Has a potential problem been observed with this member (failing is worse than suspect)"
+      type="boolean"
+      is="true"
+      writeable="false"/>
+    <attribute
+      name="udpPort"
+      description="The upd port the member is listening on"
+      type="int"
+      writeable="false"/>
+  </mbean>
 </mbeans-descriptors>
diff --git a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
index 6da9a79..0a9c871 100644
--- a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
@@ -1339,6 +1339,10 @@ public abstract class AbstractReplicatedMap extends ConcurrentHashMap implements
             }
         }
 
+        /**
+         * @deprecated  Unused - will be removed in Tomcat 8.0.x
+         */
+        @Deprecated
         public MapMessage() {}
 
         public MapMessage(byte[] mapId,int msgtype, boolean diff,
@@ -1448,7 +1452,11 @@ public abstract class AbstractReplicatedMap extends ConcurrentHashMap implements
                 throw new RuntimeException(x);
             }
         }
-        
+
+        /**
+         * @deprecated  Unused - will be removed in 8.0.x
+         */
+        @Deprecated
         protected Member[] readMembers(ObjectInput in) throws IOException, ClassNotFoundException {
             int nodecount = in.readInt();
             Member[] members = new Member[nodecount];
@@ -1460,6 +1468,10 @@ public abstract class AbstractReplicatedMap extends ConcurrentHashMap implements
             return members;
         }
         
+        /**
+         * @deprecated  Unused - will be removed in 8.0.x
+         */
+        @Deprecated
         protected void writeMembers(ObjectOutput out,Member[] members) throws IOException {
             if ( members == null ) members = new Member[0];
             out.writeInt(members.length);
diff --git a/java/org/apache/catalina/tribes/tipis/Streamable.java b/java/org/apache/catalina/tribes/tipis/Streamable.java
index 5607bb2..f7dd003 100644
--- a/java/org/apache/catalina/tribes/tipis/Streamable.java
+++ b/java/org/apache/catalina/tribes/tipis/Streamable.java
@@ -31,7 +31,10 @@ import java.io.IOException;
  * </pre></code>
  * @author Filip Hanik
  * @version 1.0
+ *
+ * @deprecated  Unused - will be removed in Tomcat 8.0.x
  */
+ at Deprecated
 public interface Streamable {
     
     /**
diff --git a/java/org/apache/catalina/tribes/transport/ReceiverBase.java b/java/org/apache/catalina/tribes/transport/ReceiverBase.java
index 2c31e38..1fadefd 100644
--- a/java/org/apache/catalina/tribes/transport/ReceiverBase.java
+++ b/java/org/apache/catalina/tribes/transport/ReceiverBase.java
@@ -63,7 +63,7 @@ public abstract class ReceiverBase implements ChannelReceiver, ListenCallback, R
     private int udpRxBufSize = 43800;
     private int udpTxBufSize = 25188;
 
-    private boolean listen = false;
+    private volatile boolean listen = false;
     private RxTaskPool pool;
     private boolean direct = true;
     private long tcpSelectorTimeout = 5000;
diff --git a/java/org/apache/catalina/tribes/transport/bio/BioReceiver.java b/java/org/apache/catalina/tribes/transport/bio/BioReceiver.java
index f1ba7ef..03cde93 100644
--- a/java/org/apache/catalina/tribes/transport/bio/BioReceiver.java
+++ b/java/org/apache/catalina/tribes/transport/bio/BioReceiver.java
@@ -30,7 +30,7 @@ import org.apache.juli.logging.LogFactory;
 /**
  *
  * @author Filip Hanik
- * @version $Id: BioReceiver.java 1059560 2011-01-16 13:54:28Z markt $
+ * @version $Id: BioReceiver.java 1358615 2012-07-07 18:39:48Z markt $
  */
 public class BioReceiver extends ReceiverBase implements Runnable {
 
@@ -143,7 +143,6 @@ public class BioReceiver extends ReceiverBase implements Runnable {
             socket.setOOBInline(getOoBInline());
             socket.setReuseAddress(getSoReuseAddress());
             socket.setSoLinger(getSoLingerOn(),getSoLingerTime());
-            socket.setTrafficClass(getSoTrafficClass());
             socket.setSoTimeout(getTimeout());
             ObjectReader reader = new ObjectReader(socket);
             task.serviceSocket(socket,reader);
diff --git a/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java b/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
index 03e1170..cf1a4c6 100644
--- a/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
+++ b/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
@@ -33,7 +33,7 @@ import org.apache.catalina.tribes.transport.MultiPointSender;
 /**
  *
  * @author Filip Hanik
- * @version $Id: MultipointBioSender.java 1033915 2010-11-11 12:40:15Z markt $
+ * @version $Id: MultipointBioSender.java 1370390 2012-08-07 17:45:38Z markt $
  *
  */
 public class MultipointBioSender extends AbstractSender implements MultiPointSender {
@@ -41,7 +41,11 @@ public class MultipointBioSender extends AbstractSender implements MultiPointSen
         // NO-OP
     }
     
-    protected long selectTimeout = 1000; 
+    /**
+     * @deprecated  Unused - will be removed in Tomcat 8.0.x
+     */
+    @Deprecated
+    protected final long selectTimeout = 1000;
     protected HashMap<Member, BioSender> bioSenders =
         new HashMap<Member, BioSender>();
 
diff --git a/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java b/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java
index 05a593d..12e1365 100644
--- a/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java
+++ b/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java
@@ -30,6 +30,7 @@ import java.nio.channels.SocketChannel;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.catalina.tribes.io.ObjectReader;
 import org.apache.catalina.tribes.transport.AbstractRxTask;
@@ -42,7 +43,7 @@ import org.apache.juli.logging.LogFactory;
 
 /**
  * @author Filip Hanik
- * @version $Id: NioReceiver.java 1212120 2011-12-08 20:57:33Z markt $
+ * @version $Id: NioReceiver.java 1405682 2012-11-05 00:25:03Z markt $
  */
 public class NioReceiver extends ReceiverBase implements Runnable {
 
@@ -58,7 +59,7 @@ public class NioReceiver extends ReceiverBase implements Runnable {
      */
     private static final String info = "NioReceiver/1.0";
 
-    private Selector selector = null;
+    private AtomicReference<Selector> selector = new AtomicReference<Selector>();
     private ServerSocketChannel serverChannel = null;
     private DatagramChannel datagramChannel = null;
 
@@ -136,7 +137,7 @@ public class NioReceiver extends ReceiverBase implements Runnable {
             // Selector.open() isn't thread safe
             // http://bugs.sun.com/view_bug.do?bug_id=6427854
             // Affects 1.6.0_29, fixed in 1.7.0_01
-            selector = Selector.open();
+            this.selector.set(Selector.open());
         }
         // set the port the server channel will listen to
         //serverSocket.bind(new InetSocketAddress(getBind(), getTcpListenPort()));
@@ -144,27 +145,34 @@ public class NioReceiver extends ReceiverBase implements Runnable {
         // set non-blocking mode for the listening socket
         serverChannel.configureBlocking(false);
         // register the ServerSocketChannel with the Selector
-        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
+        serverChannel.register(this.selector.get(), SelectionKey.OP_ACCEPT);
 
         //set up the datagram channel
         if (this.getUdpPort()>0) {
             datagramChannel = DatagramChannel.open();
-            datagramChannel.configureBlocking(false);
+            configureDatagraChannel();
             //bind to the address to avoid security checks
             bindUdp(datagramChannel.socket(),getUdpPort(),getAutoBind());
         }
+    }
 
-
-
+    private void configureDatagraChannel() throws IOException {
+        datagramChannel.configureBlocking(false);
+        datagramChannel.socket().setSendBufferSize(getUdpTxBufSize());
+        datagramChannel.socket().setReceiveBufferSize(getUdpRxBufSize());
+        datagramChannel.socket().setReuseAddress(getSoReuseAddress());
+        datagramChannel.socket().setSoTimeout(getTimeout());
+        datagramChannel.socket().setTrafficClass(getSoTrafficClass());
     }
 
     public void addEvent(Runnable event) {
+        Selector selector = this.selector.get();
         if ( selector != null ) {
             synchronized (events) {
                 events.add(event);
             }
             if ( log.isTraceEnabled() ) log.trace("Adding event to selector:"+event);
-            if ( isListening() && selector!=null ) selector.wakeup();
+            if ( isListening() ) selector.wakeup();
         }
     }
 
@@ -204,7 +212,7 @@ public class NioReceiver extends ReceiverBase implements Runnable {
         long now = System.currentTimeMillis();
         if ( (now-lastCheck) < getSelectorTimeout() ) return;
         //timeout
-        Selector tmpsel = selector;
+        Selector tmpsel = this.selector.get();
         Set<SelectionKey> keys =  (isListening()&&tmpsel!=null)?tmpsel.keys():null;
         if ( keys == null ) return;
         for (Iterator<SelectionKey> iter = keys.iterator(); iter.hasNext();) {
@@ -257,15 +265,10 @@ public class NioReceiver extends ReceiverBase implements Runnable {
         setListen(true);
 
         // Avoid NPEs if selector is set to null on stop.
-        Selector selector = this.selector;
+        Selector selector = this.selector.get();
 
         if (selector!=null && datagramChannel!=null) {
             ObjectReader oreader = new ObjectReader(MAX_UDP_SIZE); //max size for a datagram packet
-            datagramChannel.socket().setSendBufferSize(getUdpTxBufSize());
-            datagramChannel.socket().setReceiveBufferSize(getUdpRxBufSize());
-            datagramChannel.socket().setReuseAddress(getSoReuseAddress());
-            datagramChannel.socket().setSoTimeout(getTimeout());
-            datagramChannel.socket().setTrafficClass(getSoTrafficClass());
             registerChannel(selector,datagramChannel,SelectionKey.OP_READ,oreader);
         }
 
@@ -298,14 +301,13 @@ public class NioReceiver extends ReceiverBase implements Runnable {
                     if (key.isAcceptable()) {
                         ServerSocketChannel server = (ServerSocketChannel) key.channel();
                         SocketChannel channel = server.accept();
-                        channel.socket().setReceiveBufferSize(getRxBufSize());
+                        channel.socket().setReceiveBufferSize(getTxBufSize());
                         channel.socket().setSendBufferSize(getTxBufSize());
                         channel.socket().setTcpNoDelay(getTcpNoDelay());
                         channel.socket().setKeepAlive(getSoKeepAlive());
                         channel.socket().setOOBInline(getOoBInline());
                         channel.socket().setReuseAddress(getSoReuseAddress());
                         channel.socket().setSoLinger(getSoLingerOn(),getSoLingerTime());
-                        channel.socket().setTrafficClass(getSoTrafficClass());
                         channel.socket().setSoTimeout(getTimeout());
                         Object attach = new ObjectReader(channel);
                         registerChannel(selector,
@@ -359,6 +361,7 @@ public class NioReceiver extends ReceiverBase implements Runnable {
      */
     protected void stopListening() {
         setListen(false);
+        Selector selector = this.selector.get();
         if (selector != null) {
             try {
                 selector.wakeup();
@@ -366,14 +369,13 @@ public class NioReceiver extends ReceiverBase implements Runnable {
             } catch (Exception x) {
                 log.error("Unable to close cluster receiver selector.", x);
             } finally {
-                selector = null;
+                this.selector.set(null);
             }
         }
     }
 
     private void closeSelector() throws IOException {
-        Selector selector = this.selector;
-        this.selector = null;
+        Selector selector = this.selector.getAndSet(null);
         if (selector==null) return;
         try {
             Iterator<SelectionKey> it = selector.keys().iterator();
diff --git a/java/org/apache/catalina/tribes/transport/nio/NioSender.java b/java/org/apache/catalina/tribes/transport/nio/NioSender.java
index 8cedb54..0913eea 100644
--- a/java/org/apache/catalina/tribes/transport/nio/NioSender.java
+++ b/java/org/apache/catalina/tribes/transport/nio/NioSender.java
@@ -20,7 +20,6 @@ package org.apache.catalina.tribes.transport.nio;
 import java.io.EOFException;
 import java.io.IOException;
 import java.net.InetSocketAddress;
-import java.net.SocketException;
 import java.nio.ByteBuffer;
 import java.nio.channels.DatagramChannel;
 import java.nio.channels.SelectionKey;
@@ -132,13 +131,9 @@ public class NioSender extends AbstractSender {
         return false;
     }
 
-    private void completeConnect() throws SocketException {
-        //we connected, register ourselves for writing
-        setConnected(true);
-        connecting = false;
-        setRequestCount(0);
-        setConnectTime(System.currentTimeMillis());
+    private void configureSocket() throws IOException {
         if (socketChannel!=null) {
+            socketChannel.configureBlocking(false);
             socketChannel.socket().setSendBufferSize(getTxBufSize());
             socketChannel.socket().setReceiveBufferSize(getRxBufSize());
             socketChannel.socket().setSoTimeout((int)getTimeout());
@@ -150,6 +145,7 @@ public class NioSender extends AbstractSender {
             socketChannel.socket().setSoLinger(getSoLingerOn(),getSoLingerTime());
             socketChannel.socket().setTrafficClass(getSoTrafficClass());
         } else if (dataChannel!=null) {
+            dataChannel.configureBlocking(false);
             dataChannel.socket().setSendBufferSize(getUdpTxBufSize());
             dataChannel.socket().setReceiveBufferSize(getUdpRxBufSize());
             dataChannel.socket().setSoTimeout((int)getTimeout());
@@ -158,6 +154,13 @@ public class NioSender extends AbstractSender {
         }
     }
 
+    private void completeConnect() {
+        //we connected, register ourselves for writing
+        setConnected(true);
+        connecting = false;
+        setRequestCount(0);
+        setConnectTime(System.currentTimeMillis());
+    }
 
 
     protected boolean read(SelectionKey key) throws IOException {
@@ -232,7 +235,7 @@ public class NioSender extends AbstractSender {
             InetSocketAddress daddr = new InetSocketAddress(getAddress(),getUdpPort());
             if ( dataChannel != null ) throw new IOException("Datagram channel has already been established. Connection might be in progress.");
             dataChannel = DatagramChannel.open();
-            dataChannel.configureBlocking(false);
+            configureSocket();
             dataChannel.connect(daddr);
             completeConnect();
             dataChannel.register(getSelector(),SelectionKey.OP_WRITE, this);
@@ -241,7 +244,7 @@ public class NioSender extends AbstractSender {
             InetSocketAddress addr = new InetSocketAddress(getAddress(),getPort());
             if ( socketChannel != null ) throw new IOException("Socket channel has already been established. Connection might be in progress.");
             socketChannel = SocketChannel.open();
-            socketChannel.configureBlocking(false);
+            configureSocket();
             if ( socketChannel.connect(addr) ) {
                 completeConnect();
                 socketChannel.register(getSelector(), SelectionKey.OP_WRITE, this);
diff --git a/java/org/apache/catalina/util/ConcurrentMessageDigest.java b/java/org/apache/catalina/util/ConcurrentMessageDigest.java
new file mode 100644
index 0000000..a84a48e
--- /dev/null
+++ b/java/org/apache/catalina/util/ConcurrentMessageDigest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.util;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * A thread safe wrapper around {@link MessageDigest} that does not make use
+ * of ThreadLocal and - broadly - only creates enough MessageDigest objects
+ * to satisfy the concurrency requirements.
+ */
+public class ConcurrentMessageDigest {
+
+    private static final String MD5 = "MD5";
+
+    private static final Map<String,Queue<MessageDigest>> queues =
+            new HashMap<String,Queue<MessageDigest>>();
+
+
+    private ConcurrentMessageDigest() {
+        // Hide default constructor for this utility class
+    }
+
+    static {
+        try {
+            // Init commonly used algorithms
+            init(MD5);
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    public static byte[] digestMD5(byte[] input) {
+        return digest(MD5, input);
+    }
+
+    public static byte[] digest(String algorithm, byte[] input) {
+
+        Queue<MessageDigest> queue = queues.get(algorithm);
+        if (queue == null) {
+            throw new IllegalStateException("Must call init() first");
+        }
+
+        MessageDigest md = queue.poll();
+        if (md == null) {
+            try {
+                md = MessageDigest.getInstance(algorithm);
+            } catch (NoSuchAlgorithmException e) {
+                // Ignore. Impossible if init() has been successfully called
+                // first.
+                throw new IllegalStateException("Must call init() first");
+            }
+        }
+
+        byte[] result = md.digest(input);
+
+        queue.add(md);
+
+        return result;
+    }
+
+
+    /**
+     * Ensures that {@link #digest(String, byte[])} will support the specified
+     * algorithm. This method <b>must</b> be called and return successfully
+     * before using {@link #digest(String, byte[])}.
+     *
+     * @param algorithm The message digest algorithm to be supported
+     *
+     * @throws NoSuchAlgorithmException If the algorithm is not supported by the
+     *                                  JVM
+     */
+    public static void init(String algorithm) throws NoSuchAlgorithmException {
+        synchronized (queues) {
+            if (!queues.containsKey(algorithm)) {
+                MessageDigest md = MessageDigest.getInstance(algorithm);
+                Queue<MessageDigest> queue =
+                        new ConcurrentLinkedQueue<MessageDigest>();
+                queue.add(md);
+                queues.put(algorithm, queue);
+            }
+        }
+    }
+}
diff --git a/java/org/apache/catalina/util/DOMWriter.java b/java/org/apache/catalina/util/DOMWriter.java
index 31b9fa1..d901ad8 100644
--- a/java/org/apache/catalina/util/DOMWriter.java
+++ b/java/org/apache/catalina/util/DOMWriter.java
@@ -61,7 +61,10 @@ public class DOMWriter {
    /** Canonical output. */
    protected boolean canonical;
 
-
+   /**
+    * @deprecated   Unused - will be removed in 8.0.x
+    */
+   @Deprecated
    public DOMWriter(String encoding, boolean canonical)
    throws UnsupportedEncodingException {
       out = new PrintWriter(new OutputStreamWriter(System.out, encoding));
@@ -72,7 +75,12 @@ public class DOMWriter {
    // Constructors
    //
 
-   /** Default constructor. */
+   /**
+    * Default constructor.
+    *
+    * @deprecated   Unused - will be removed in 8.0.x
+    */
+   @Deprecated
    public DOMWriter(boolean canonical) throws UnsupportedEncodingException {
       this( getWriterEncoding(), canonical);
    }
@@ -82,10 +90,18 @@ public class DOMWriter {
         this.canonical = canonical;
     }
 
+   /**
+    * @deprecated   Unused - will be removed in 8.0.x
+    */
+   @Deprecated
    public boolean getQualifiedNames() {
       return this.qualifiedNames;
    }
 
+   /**
+    * @deprecated   Unnecessary - will be removed in 8.0.x
+    */
+   @Deprecated
    public void setQualifiedNames(boolean qualifiedNames) {
       this.qualifiedNames = qualifiedNames;
    }
@@ -94,6 +110,10 @@ public class DOMWriter {
       return (PRINTWRITER_ENCODING);
    }// getWriterEncoding
 
+   /**
+    * @deprecated   Unused - will be removed in 8.0.x
+    */
+   @Deprecated
    public static void  setWriterEncoding( String encoding ) {
       if( encoding.equalsIgnoreCase( "DEFAULT" ) )
          PRINTWRITER_ENCODING  = "UTF8";
@@ -104,6 +124,10 @@ public class DOMWriter {
    }// setWriterEncoding
 
 
+   /**
+    * @deprecated   Unused - will be removed in 8.0.x
+    */
+   @Deprecated
    public static boolean isValidJavaEncoding( String encoding ) {
       for ( int i = 0; i < MIME2JAVA_ENCODINGS.length; i++ )
          if ( encoding.equals( MIME2JAVA_ENCODINGS[i] ) )
diff --git a/java/org/apache/catalina/util/DateTool.java b/java/org/apache/catalina/util/DateTool.java
index 9d5e7c4..82bc3ac 100644
--- a/java/org/apache/catalina/util/DateTool.java
+++ b/java/org/apache/catalina/util/DateTool.java
@@ -31,7 +31,10 @@ import java.util.TimeZone;
  * @author James Todd [gonzo at eng.sun.com]
  * @author Costin Manolache
  * @author fhanik
+ *
+ * @deprecated  Mostly unused and will be removed in 8.0.x onwards
  */
+ at Deprecated
 public class DateTool {
 
     /**
diff --git a/java/org/apache/catalina/util/LifecycleBase.java b/java/org/apache/catalina/util/LifecycleBase.java
index 7e426a1..52de9be 100644
--- a/java/org/apache/catalina/util/LifecycleBase.java
+++ b/java/org/apache/catalina/util/LifecycleBase.java
@@ -242,7 +242,7 @@ public abstract class LifecycleBase implements Lifecycle {
             setStateInternal(LifecycleState.STOPPED, null, false);
 
             destroy();
-        } else {
+        } else if (!state.equals(LifecycleState.FAILED)){
             // Shouldn't be necessary but acts as a check that sub-classes are
             // doing what they are supposed to.
             if (!state.equals(LifecycleState.STOPPING)) {
@@ -272,7 +272,8 @@ public abstract class LifecycleBase implements Lifecycle {
                 stop();
             } catch (LifecycleException e) {
                 // Just log. Still want to destroy.
-                log.warn(sm.getString("lifecycleBase.destroyStopFail"), e);
+                log.warn(sm.getString(
+                        "lifecycleBase.destroyStopFail", toString()), e);
             }
         }
 
diff --git a/java/org/apache/catalina/util/MD5Encoder.java b/java/org/apache/catalina/util/MD5Encoder.java
index 65b4702..4dfe1ad 100644
--- a/java/org/apache/catalina/util/MD5Encoder.java
+++ b/java/org/apache/catalina/util/MD5Encoder.java
@@ -27,12 +27,20 @@ package org.apache.catalina.util;
  * of the digest.
  *
  * @author Remy Maucherat
- * @version $Id: MD5Encoder.java 939305 2010-04-29 13:43:39Z kkolinko $
+ * @version $Id: MD5Encoder.java 1364451 2012-07-22 22:23:22Z markt $
  */
 
 public final class MD5Encoder {
 
 
+    /**
+     * @deprecated  Will be made private in Tomcat 8.0.x
+     */
+    @Deprecated
+    public MD5Encoder() {
+        // NOOP
+    }
+
     // ----------------------------------------------------- Instance Variables
 
 
@@ -50,7 +58,7 @@ public final class MD5Encoder {
      * @param binaryData Array containing the digest
      * @return Encoded MD5, or null if encoding failed
      */
-    public String encode( byte[] binaryData ) {
+    public static String encode( byte[] binaryData ) {
 
         if (binaryData.length != 16)
             return null;
diff --git a/java/org/apache/catalina/util/RequestUtil.java b/java/org/apache/catalina/util/RequestUtil.java
index ff5a017..4a074f2 100644
--- a/java/org/apache/catalina/util/RequestUtil.java
+++ b/java/org/apache/catalina/util/RequestUtil.java
@@ -31,7 +31,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Tim Tye
- * @version $Id: RequestUtil.java 1239053 2012-02-01 10:52:00Z markt $
+ * @version $Id: RequestUtil.java 1370978 2012-08-08 21:20:42Z markt $
  */
 public final class RequestUtil {
 
@@ -249,7 +249,10 @@ public final class RequestUtil {
      * @param enc The encoding to use; if null, the default encoding is used
      * @exception IllegalArgumentException if a '%' character is not followed
      * by a valid 2-digit hexadecimal number
+     *
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static String URLDecode(byte[] bytes, String enc) {
         return URLDecode(bytes, enc, false);
     }
diff --git a/java/org/apache/catalina/valves/AccessLogValve.java b/java/org/apache/catalina/valves/AccessLogValve.java
index 1528475..1d37a1b 100644
--- a/java/org/apache/catalina/valves/AccessLogValve.java
+++ b/java/org/apache/catalina/valves/AccessLogValve.java
@@ -44,6 +44,7 @@ import org.apache.catalina.AccessLog;
 import org.apache.catalina.Globals;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.LifecycleState;
+import org.apache.catalina.Session;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
 import org.apache.coyote.RequestInfo;
@@ -110,6 +111,8 @@ import org.apache.tomcat.util.buf.B2CConverter;
  * <li><code>%{xxx}c</code> for a specific cookie
  * <li><code>%{xxx}r</code> xxx is an attribute in the ServletRequest
  * <li><code>%{xxx}s</code> xxx is an attribute in the HttpSession
+ * <li><code>%{xxx}t</code> xxx is an enhanced SimpleDateFormat pattern
+ * (see Configuration Reference document for details on supported time patterns)
  * </ul>
  *
  * <p>
@@ -153,7 +156,7 @@ import org.apache.tomcat.util.buf.B2CConverter;
  * @author Takayuki Kaneko
  * @author Peter Rossbach
  *
- * @version $Id: AccessLogValve.java 1301255 2012-03-15 22:47:40Z markt $
+ * @version $Id: AccessLogValve.java 1410500 2012-11-16 17:31:02Z markt $
  */
 
 public class AccessLogValve extends ValveBase implements AccessLog {
@@ -298,28 +301,28 @@ public class AccessLogValve extends ValveBase implements AccessLog {
      * <p>This class uses a small thread local first level cache and a bigger
      * synchronized global second level cache.</p>
      */
-    private static class DateFormatCache {
+    protected static class DateFormatCache {
 
-        private class Cache {
+        protected class Cache {
 
             /* CLF log format */
             private static final String cLFFormat = "dd/MMM/yyyy:HH:mm:ss";
 
             /* Second used to retrieve CLF format in most recent invocation */
-            private long previousSeconds = 0L;
+            private long previousSeconds = Long.MIN_VALUE;
             /* Value of CLF format retrieved in most recent invocation */
             private String previousFormat = "";
 
             /* First second contained in cache */
-            private long first = 0L;
+            private long first = Long.MIN_VALUE;
             /* Last second contained in cache */
-            private long last = 0L;
+            private long last = Long.MIN_VALUE;
             /* Index of "first" in the cyclic cache */
             private int offset = 0;
             /* Helper object to be able to call SimpleDateFormat.format(). */
             private final Date currentDate = new Date();
 
-            private final String cache[];
+            protected final String cache[];
             private SimpleDateFormat formatter;
             private boolean isCLF = false;
 
@@ -388,14 +391,16 @@ public class AccessLogValve extends ValveBase implements AccessLog {
                     for (int i = 1; i < seconds - last; i++) {
                         cache[(index + cacheSize - i) % cacheSize] = null;
                     }
-                    first = seconds - cacheSize;
+                    first = seconds - (cacheSize - 1);
                     last = seconds;
+                    offset = (index + 1) % cacheSize;
                 } else if (seconds < first) {
                     for (int i = 1; i < first - seconds; i++) {
                         cache[(index + i) % cacheSize] = null;
                     }
                     first = seconds;
-                    last = seconds + cacheSize;
+                    last = seconds + (cacheSize - 1);
+                    offset = index;
                 }
 
                 /* Last step: format new timestamp either using
@@ -427,10 +432,10 @@ public class AccessLogValve extends ValveBase implements AccessLog {
 
         private final Locale cacheDefaultLocale;
         private final DateFormatCache parent;
-        private final Cache cLFCache;
+        protected final Cache cLFCache;
         private final HashMap<String, Cache> formatCache = new HashMap<String, Cache>();
 
-        private DateFormatCache(int size, Locale loc, DateFormatCache parent) {
+        protected DateFormatCache(int size, Locale loc, DateFormatCache parent) {
             cacheSize = size;
             cacheDefaultLocale = loc;
             this.parent = parent;
@@ -494,8 +499,7 @@ public class AccessLogValve extends ValveBase implements AccessLog {
      * The system time when we last updated the Date that this valve
      * uses for log lines.
      */
-    private static final ThreadLocal<Date> localDate =
-            new ThreadLocal<Date>() {
+    private static final ThreadLocal<Date> localDate = new ThreadLocal<Date>() {
         @Override
         protected Date initialValue() {
             return new Date();
@@ -505,7 +509,7 @@ public class AccessLogValve extends ValveBase implements AccessLog {
     /**
      * The list of our format types.
      */
-    private static enum formatType {
+    private static enum FormatType {
         CLF, SEC, MSEC, MSEC_FRAC, SDF
     }
 
@@ -1125,11 +1129,8 @@ public class AccessLogValve extends ValveBase implements AccessLog {
     }
 
     /**
-     * This method returns a Date object that is accurate to within one second.
-     * If a thread calls this method to get a Date and it's been less than 1
-     * second since a new Date was created, this method simply gives out the
-     * same Date again so that the system doesn't spend time creating Date
-     * objects unnecessarily.
+     * This method returns a ThreadLocal Date object that is set to the
+     * specified time. This saves creating a new Date object for every request.
      *
      * @return Date
      */
@@ -1432,7 +1433,7 @@ public class AccessLogValve extends ValveBase implements AccessLog {
         /* Whether to use begin of request or end of response as the timestamp */
         private boolean usesBegin = false;
         /* The format type */
-        private formatType type = formatType.CLF;
+        private FormatType type = FormatType.CLF;
         /* Whether we need to postprocess by adding milliseconds */
         private boolean usesMsecs = false;
 
@@ -1484,15 +1485,15 @@ public class AccessLogValve extends ValveBase implements AccessLog {
                     format = format.substring(4);
                 }
                 if (format.length() == 0) {
-                    type = formatType.CLF;
+                    type = FormatType.CLF;
                 } else if (format.equals(secFormat)) {
-                    type = formatType.SEC;
+                    type = FormatType.SEC;
                 } else if (format.equals(msecFormat)) {
-                    type = formatType.MSEC;
+                    type = FormatType.MSEC;
                 } else if (format.equals(msecFractionFormat)) {
-                    type = formatType.MSEC_FRAC;
+                    type = FormatType.MSEC_FRAC;
                 } else {
-                    type = formatType.SDF;
+                    type = FormatType.SDF;
                     format = tidyFormat(format);
                 }
             }
@@ -1726,15 +1727,15 @@ public class AccessLogValve extends ValveBase implements AccessLog {
         @Override
         public void addElement(StringBuilder buf, Date date, Request request,
                 Response response, long time) {
-            if (request != null) {
-                if (request.getSession(false) != null) {
-                    buf.append(request.getSessionInternal(false)
-                            .getIdInternal());
-                } else {
+            if (request == null) {
+                buf.append('-');
+            } else {
+                Session session = request.getSessionInternal(false);
+                if (session == null) {
                     buf.append('-');
+                } else {
+                    buf.append(session.getIdInternal());
                 }
-            } else {
-                buf.append('-');
             }
         }
     }
diff --git a/java/org/apache/catalina/valves/ErrorReportValve.java b/java/org/apache/catalina/valves/ErrorReportValve.java
index f666755..7514b4a 100644
--- a/java/org/apache/catalina/valves/ErrorReportValve.java
+++ b/java/org/apache/catalina/valves/ErrorReportValve.java
@@ -19,6 +19,7 @@ package org.apache.catalina.valves;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Scanner;
 
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
@@ -43,7 +44,7 @@ import org.apache.tomcat.util.ExceptionUtils;
  * @author <a href="mailto:nicolaken at supereva.it">Nicola Ken Barozzi</a> Aisa
  * @author <a href="mailto:stefano at apache.org">Stefano Mazzocchi</a>
  * @author Yoav Shapira
- * @version $Id: ErrorReportValve.java 1348777 2012-06-11 09:50:03Z markt $
+ * @version $Id: ErrorReportValve.java 1372132 2012-08-12 15:42:33Z markt $
  */
 
 public class ErrorReportValve extends ValveBase {
@@ -166,7 +167,11 @@ public class ErrorReportValve extends ValveBase {
         String message = RequestUtil.filter(response.getMessage());
         if (message == null) {
             if (throwable != null) {
-                message = RequestUtil.filter(throwable.getMessage());
+                String exceptionMessage = throwable.getMessage();
+                if (exceptionMessage != null && exceptionMessage.length() > 0) {
+                    message = RequestUtil.filter(
+                            (new Scanner(exceptionMessage)).nextLine());
+                }
             }
             if (message == null) {
                 message = "";
@@ -176,7 +181,7 @@ public class ErrorReportValve extends ValveBase {
         // Do nothing if there is no report for the specified status code
         String report = null;
         try {
-            report = sm.getString("http." + statusCode, message);
+            report = sm.getString("http." + statusCode);
         } catch (Throwable t) {
             ExceptionUtils.handleThrowable(t);
         }
diff --git a/java/org/apache/catalina/valves/LocalStrings.properties b/java/org/apache/catalina/valves/LocalStrings.properties
index 17f78a1..cde65ce 100644
--- a/java/org/apache/catalina/valves/LocalStrings.properties
+++ b/java/org/apache/catalina/valves/LocalStrings.properties
@@ -52,49 +52,67 @@ sslValve.certError=Failed to process certificate string [{0}] to create a java.s
 sslValve.invalidProvider=The SSL provider specified on the connector associated with this request of [{0}] is invalid. The certificate data could not be processed.
 
 #Stuck thread detection Valve
-stuckThreadDetectionValve.notifyStuckThreadDetected=Thread "{0}" has been active for {1} milliseconds (since {2}) to serve the same request for {4} and may be stuck (configured threshold for this StuckThreadDetectionValve is {5} seconds). There is/are {3} thread(s) in total that are monitored by this Valve and may be stuck.
-stuckThreadDetectionValve.notifyStuckThreadCompleted=Thread "{0}" was previously reported to be stuck but has completed. It was active for approximately {1} milliseconds.{2,choice,0#|0< There is/are still {2} thread(s) that are monitored by this Valve and may be stuck.}
+stuckThreadDetectionValve.notifyStuckThreadDetected=Thread "{0}" (id={6}) has been active for {1} milliseconds (since {2}) to serve the same request for {4} and may be stuck (configured threshold for this StuckThreadDetectionValve is {5} seconds). There is/are {3} thread(s) in total that are monitored by this Valve and may be stuck.
+stuckThreadDetectionValve.notifyStuckThreadCompleted=Thread "{0}" (id={3}) was previously reported to be stuck but has completed. It was active for approximately {1} milliseconds.{2,choice,0#|0< There is/are still {2} thread(s) that are monitored by this Valve and may be stuck.}
 
 # HTTP status reports
-http.100=The client may continue ({0}).
-http.101=The server is switching protocols according to the "Upgrade" header ({0}).
-http.201=The request succeeded and a new resource ({0}) has been created on the server.
-http.202=This request was accepted for processing, but has not been completed ({0}).
-http.203=The meta information presented by the client did not originate from the server ({0}).
-http.204=The request succeeded but there is no information to return ({0}).
-http.205=The client should reset the document view which caused this request to be sent ({0}).
-http.206=The server has fulfilled a partial GET request for this resource ({0}).
-http.207=Multiple status values have been returned ({0}).
-http.300=The requested resource ({0}) corresponds to any one of a set of representations, each with its own specific location.
-http.301=The requested resource ({0}) has moved permanently to a new location.
-http.302=The requested resource ({0}) has moved temporarily to a new location.
-http.303=The response to this request can be found under a different URI ({0}).
-http.304=The requested resource ({0}) is available and has not been modified.
-http.305=The requested resource ({0}) must be accessed through the proxy given by the "Location" header.
-http.400=The request sent by the client was syntactically incorrect ({0}).
-http.401=This request requires HTTP authentication ({0}).
-http.402=Payment is required for access to this resource ({0}).
-http.403=Access to the specified resource ({0}) has been forbidden.
-http.404=The requested resource ({0}) is not available.
-http.405=The specified HTTP method is not allowed for the requested resource ({0}).
-http.406=The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ({0}).
-http.407=The client must first authenticate itself with the proxy ({0}).
-http.408=The client did not produce a request within the time that the server was prepared to wait ({0}).
-http.409=The request could not be completed due to a conflict with the current state of the resource ({0}).
-http.410=The requested resource ({0}) is no longer available, and no forwarding address is known.
-http.411=This request cannot be handled without a defined content length ({0}).
-http.412=A specified precondition has failed for this request ({0}).
+# All status codes registered with IANA can be found at
+# http://www.iana.org/assignments/http-status-codes/http-status-codes.xml
+# The list might be kept in sync with the one in
+# org/apache/tomcat/util/http/res/LocalStrings.properties.
+http.100=The client may continue.
+http.101=The server is switching protocols according to the "Upgrade" header.
+http.102=The server has accepted the complete request, but has not yet completed it.
+http.201=The request succeeded and a new resource has been created on the server.
+http.202=This request was accepted for processing, but has not been completed.
+http.203=The meta information presented by the client did not originate from the server.
+http.204=The request succeeded but there is no information to return.
+http.205=The client should reset the document view which caused this request to be sent.
+http.206=The server has fulfilled a partial GET request for this resource.
+http.207=Multiple status values have been returned.
+http.208=This collection binding was already reported.
+http.226=The response is a representation of the result of one or more instance-manipulations applied to the current instance.
+http.300=The requested resource corresponds to any one of a set of representations, each with its own specific location.
+http.301=The requested resource has moved permanently to a new location.
+http.302=The requested resource has moved temporarily to a new location.
+http.303=The response to this request can be found under a different URI.
+http.304=The requested resource is available and has not been modified.
+http.305=The requested resource must be accessed through the proxy given by the "Location" header.
+http.307=The requested resource resides temporarily under a different URI.
+http.308=The target resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs.
+http.400=The request sent by the client was syntactically incorrect.
+http.401=This request requires HTTP authentication.
+http.402=Payment is required for access to this resource.
+http.403=Access to the specified resource has been forbidden.
+http.404=The requested resource is not available.
+http.405=The specified HTTP method is not allowed for the requested resource.
+http.406=The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
+http.407=The client must first authenticate itself with the proxy.
+http.408=The client did not produce a request within the time that the server was prepared to wait.
+http.409=The request could not be completed due to a conflict with the current state of the resource.
+http.410=The requested resource is no longer available, and no forwarding address is known.
+http.411=This request cannot be handled without a defined content length.
+http.412=A specified precondition has failed for this request.
 http.413=The request entity is larger than the server is willing or able to process.
-http.414=The server refused this request because the request URI was too long ({0}).
-http.415=The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ({0}).
-http.416=The requested byte range cannot be satisfied ({0}).
-http.417=The expectation given in the "Expect" request header ({0}) could not be fulfilled.
-http.422=The server understood the content type and syntax of the request but was unable to process the contained instructions ({0}).
-http.423=The source or destination resource of a method is locked ({0}).
-http.500=The server encountered an internal error ({0}) that prevented it from fulfilling this request.
-http.501=The server does not support the functionality needed to fulfill this request ({0}).
-http.502=This server received an invalid response from a server it consulted when acting as a proxy or gateway ({0}).
-http.503=The requested service ({0}) is not currently available.
-http.504=The server received a timeout from an upstream server while acting as a gateway or proxy ({0}).
-http.505=The server does not support the requested HTTP protocol version ({0}).
-http.507=The resource does not have sufficient space to record the state of the resource after execution of this method ({0}).
+http.414=The server refused this request because the request URI was too long.
+http.415=The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.
+http.416=The requested byte range cannot be satisfied.
+http.417=The expectation given in the "Expect" request header could not be fulfilled.
+http.422=The server understood the content type and syntax of the request but was unable to process the contained instructions.
+http.423=The source or destination resource of a method is locked.
+http.424=The method could not be performed on the resource because the requested action depended on another action and that action failed.
+http.426=The request can only be completed after a protocol upgrade.
+http.428=The request is required to be conditional.
+http.429=The user has sent too many requests in a given amount of time.
+http.431=The server refused this request because the request header fields are too large.
+http.500=The server encountered an internal error that prevented it from fulfilling this request.
+http.501=The server does not support the functionality needed to fulfill this request.
+http.502=This server received an invalid response from a server it consulted when acting as a proxy or gateway.
+http.503=The requested service is not currently available.
+http.504=The server received a timeout from an upstream server while acting as a gateway or proxy.
+http.505=The server does not support the requested HTTP protocol version.
+http.506=The chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process.
+http.507=The resource does not have sufficient space to record the state of the resource after execution of this method.
+http.508=The server terminated an operation because it encountered an infinite loop.
+http.510=The policy for accessing the resource has not been met in the request.
+http.511=The client needs to authenticate to gain network access.
diff --git a/java/org/apache/catalina/valves/LocalStrings_es.properties b/java/org/apache/catalina/valves/LocalStrings_es.properties
index 5d25459..cf98c25 100644
--- a/java/org/apache/catalina/valves/LocalStrings_es.properties
+++ b/java/org/apache/catalina/valves/LocalStrings_es.properties
@@ -37,48 +37,48 @@ remoteIpValve.syntax = Se han suministrado expresiones regulares [{0}] no v\u00E
 remoteIpValve.invalidPortHeader = Valor inv\u00E1lido [{0}] hallado para el puerto en cabecera HTTP [{1}]
 sslValve.certError = No pude procesar cadena de certificado [{0}] para crear un objeto  java.security.cert.X509Certificate
 sslValve.invalidProvider = El proveedor de SSL especificado en el conecto asociado con este requerimiento de [{0}] ies inv\u00E1lido. No se pueden procesar los datos del certificado.
-stuckThreadDetectionValve.notifyStuckThreadDetected = El hilo  "{0}" ha estado activo durante {1} miilisegundos (desde {2}) para servir el mismo requerimiento para {4} y puede estar atascado (el umbral configurado para este StuckThreadDetectionValve es de {5} segundos). Hay {3} hilo(s) en total que son monitorizados por esta V\u00E1lvula y pueden estar atascados.
-stuckThreadDetectionValve.notifyStuckThreadCompleted = El hilo "{0}", que previamente se report\u00F3 como atascado, se ha completado. Estuvo activo por aproximadamente {1} milisegundos. {2, choice,0\#|0< Hay a\u00FAn {2} hilo(s) que son monitorizados por esta V\u00E1lvula y pueden estar atascados.}
+stuckThreadDetectionValve.notifyStuckThreadDetected = El hilo  "{0}" (id={6}) ha estado activo durante {1} miilisegundos (desde {2}) para servir el mismo requerimiento para {4} y puede estar atascado (el umbral configurado para este StuckThreadDetectionValve es de {5} segundos). Hay {3} hilo(s) en total que son monitorizados por esta V\u00E1lvula y pueden estar atascados.
+stuckThreadDetectionValve.notifyStuckThreadCompleted = El hilo "{0}" (id={3}), que previamente se report\u00F3 como atascado, se ha completado. Estuvo activo por aproximadamente {1} milisegundos. {2, choice,0\#|0< Hay a\u00FAn {2} hilo(s) que son monitorizados por esta V\u00E1lvula y pueden estar atascados.}
 # HTTP status reports
-http.100 = El cliente puede continuar ({0}).
-http.101 = El servidor est\u00E1 conmutando protocolos con arreglo a la cabecera "Upgrade" ({0}).
-http.201 = El requerimiento tuvo \u00E9xito y un nuevo recurso ({0}) ha sido creado en el servidor.
-http.202 = Este requerimiento ha sido aceptado para ser procesado, pero no ha sido completado ({0}).
-http.203 = La informaci\u00F3n meta presentada por el cliente no se origin\u00F3 desde el servidor ({0}).
-http.204 = El requerimiento tuvo \u00E9xito pero no hay informaci\u00F3n que devolver ({0}).
-http.205 = El cliente no deber\u00EDa de limpiar la vista del documento que caus\u00F3 que este requerimiento fuera enviado ({0}).
-http.206 = El servidor ha rellenado paci\u00E1lmente un requerimiento GET para este recurso ({0}).
-http.207 = Se han devuelto valores m\u00FAltiples de estado ({0}).
-http.300 = El recurso requerido ({0}) corresponde a una cualquiera de un conjunto de representaciones, cada una con su propia localizaci\u00F3n espec\u00EDfica.
-http.301 = El recurso requerido ({0}) ha sido movido perman\u00E9ntemente a una nueva localizaci\u00F3n.
-http.302 = El recurso requerido ({0}) ha sido movido tempor\u00E1lmente a una nueva localizaci\u00F3n.
-http.303 = La respuesta a este requerimiento se puede hallar bajo una URI diferente ({0}).
-http.304 = El recurso requerido ({0}) est\u00E1 disponible y no ha sido modificado.
-http.305 = El recurso requerido ({0}) debe de ser accedido a trav\u00E9s del apoderado (proxy) dado mediante la cabecera "Location".
-http.400 = El requerimiento enviado por el cliente era sint\u00E1cticamente incorrecto ({0}).
-http.401 = Este requerimiento requiere autenticaci\u00F3n HTTP ({0}).
-http.402 = Se requiere pago para acceder a este recurso ({0}).
-http.403 = El acceso al recurso especificado ({0}) ha sido prohibido.
-http.404 = El recurso requerido ({0}) no est\u00E1 disponible.
-http.405 = El m\u00E9todo HTTP especificado no est\u00E1 permitido para el recurso requerido ({0}).
-http.406 = El recurso identificado por este requerimiento s\u00F3lo es capaz de generar respuestas con caracter\u00EDsticas no aceptables con arreglo a las cabeceras "accept" de requerimiento ({0}).
-http.407 = El cliente debe de ser primero autenticado en el apoderado ({0}).
-http.408 = El cliente no produjo un requerimiento dentro del tiempo en que el servidor estaba preparado esperando ({0}).
-http.409 = El requerimiento no pudo ser completado debido a un conflicto con el estado actual del recurso ({0}).
-http.410 = El recurso requerido ({0}) ya no est\u00E1 disponible y no se conoce direcci\u00F3n de reenv\u00EDo.
-http.411 = Este requerimiento no puede ser manejado sin un tama\u00F1o definido de contenido ({0}).
-http.412 = Una precondici\u00F3n especificada ha fallado para este requerimiento ({0}).
+http.100 = El cliente puede continuar.
+http.101 = El servidor est\u00E1 conmutando protocolos con arreglo a la cabecera "Upgrade".
+http.201 = El requerimiento tuvo \u00E9xito y un nuevo recurso ha sido creado en el servidor.
+http.202 = Este requerimiento ha sido aceptado para ser procesado, pero no ha sido completado.
+http.203 = La informaci\u00F3n meta presentada por el cliente no se origin\u00F3 desde el servidor.
+http.204 = El requerimiento tuvo \u00E9xito pero no hay informaci\u00F3n que devolver.
+http.205 = El cliente no deber\u00EDa de limpiar la vista del documento que caus\u00F3 que este requerimiento fuera enviado.
+http.206 = El servidor ha rellenado paci\u00E1lmente un requerimiento GET para este recurso.
+http.207 = Se han devuelto valores m\u00FAltiples de estado.
+http.300 = El recurso requerido corresponde a una cualquiera de un conjunto de representaciones, cada una con su propia localizaci\u00F3n espec\u00EDfica.
+http.301 = El recurso requerido ha sido movido perman\u00E9ntemente a una nueva localizaci\u00F3n.
+http.302 = El recurso requerido ha sido movido tempor\u00E1lmente a una nueva localizaci\u00F3n.
+http.303 = La respuesta a este requerimiento se puede hallar bajo una URI diferente.
+http.304 = El recurso requerido est\u00E1 disponible y no ha sido modificado.
+http.305 = El recurso requerido debe de ser accedido a trav\u00E9s del apoderado (proxy) dado mediante la cabecera "Location".
+http.400 = El requerimiento enviado por el cliente era sint\u00E1cticamente incorrecto.
+http.401 = Este requerimiento requiere autenticaci\u00F3n HTTP.
+http.402 = Se requiere pago para acceder a este recurso.
+http.403 = El acceso al recurso especificado ha sido prohibido.
+http.404 = El recurso requerido no est\u00E1 disponible.
+http.405 = El m\u00E9todo HTTP especificado no est\u00E1 permitido para el recurso requerido.
+http.406 = El recurso identificado por este requerimiento s\u00F3lo es capaz de generar respuestas con caracter\u00EDsticas no aceptables con arreglo a las cabeceras "accept" de requerimiento.
+http.407 = El cliente debe de ser primero autenticado en el apoderado.
+http.408 = El cliente no produjo un requerimiento dentro del tiempo en que el servidor estaba preparado esperando.
+http.409 = El requerimiento no pudo ser completado debido a un conflicto con el estado actual del recurso.
+http.410 = El recurso requerido ya no est\u00E1 disponible y no se conoce direcci\u00F3n de reenv\u00EDo.
+http.411 = Este requerimiento no puede ser manejado sin un tama\u00F1o definido de contenido.
+http.412 = Una precondici\u00F3n especificada ha fallado para este requerimiento.
 http.413 = La entidad de requerimiento es mayor de lo que el servidor quiere o puede procesar.
-http.414 = El servidor rechaz\u00F3 este requerimiento porque la URI requerida era demasiado larga ({0}).
-http.415 = El servidor rechaz\u00F3 este requerimiento porque la entidad requerida se encuentra en un formato no soportado por el recurso requerido para el m\u00E9todo requerido ({0}).
-http.416 = El rango de byte requerido no puede ser satisfecho ({0}).
-http.417 = Lo que se espera dado por la cabecera "Expect" de requerimiento ({0}) no pudo ser completado.
-http.422 = El servidor entendi\u00F3 el tipo de contenido y la sint\u00E1xis del requerimiento pero no pudo procesar las instrucciones contenidas ({0}).
-http.423 = La fuente o recurso de destino de un m\u00E9todo est\u00E1 bloqueada ({0}).
-http.500 = El servidor encontr\u00F3 un error interno ({0}) que hizo que no pudiera rellenar este requerimiento.
-http.501 = El servidor no soporta la funcionalidad necesaria para rellenar este requerimiento ({0}).
-http.502 = Este servidor recibi\u00F3 una respuesta inv\u00E1lida desde un servidor que consult\u00F3 cuando actuaba como apoderado o pasarela ({0}).
-http.503 = El servicio requerido ({0}) no est\u00E1 disponible en este momento.
-http.504 = El servidor recibi\u00F3 un Tiempo Agotado desde un servidor superior cuando actuaba como pasarela o apoderado ({0}).
-http.505 = El servidor no soporta la versi\u00F3n de protocolo HTTP requerida ({0}).
-http.507 = El recurso no tiene espacio suficiente para registrar el estado del recurso tras la ejecuci\u00F3n de este m\u00E9todo ({0}).
+http.414 = El servidor rechaz\u00F3 este requerimiento porque la URI requerida era demasiado larga.
+http.415 = El servidor rechaz\u00F3 este requerimiento porque la entidad requerida se encuentra en un formato no soportado por el recurso requerido para el m\u00E9todo requerido.
+http.416 = El rango de byte requerido no puede ser satisfecho.
+http.417 = Lo que se espera dado por la cabecera "Expect" de requerimiento no pudo ser completado.
+http.422 = El servidor entendi\u00F3 el tipo de contenido y la sint\u00E1xis del requerimiento pero no pudo procesar las instrucciones contenidas.
+http.423 = La fuente o recurso de destino de un m\u00E9todo est\u00E1 bloqueada.
+http.500 = El servidor encontr\u00F3 un error interno que hizo que no pudiera rellenar este requerimiento.
+http.501 = El servidor no soporta la funcionalidad necesaria para rellenar este requerimiento.
+http.502 = Este servidor recibi\u00F3 una respuesta inv\u00E1lida desde un servidor que consult\u00F3 cuando actuaba como apoderado o pasarela.
+http.503 = El servicio requerido no est\u00E1 disponible en este momento.
+http.504 = El servidor recibi\u00F3 un Tiempo Agotado desde un servidor superior cuando actuaba como pasarela o apoderado.
+http.505 = El servidor no soporta la versi\u00F3n de protocolo HTTP requerida.
+http.507 = El recurso no tiene espacio suficiente para registrar el estado del recurso tras la ejecuci\u00F3n de este m\u00E9todo.
diff --git a/java/org/apache/catalina/valves/LocalStrings_fr.properties b/java/org/apache/catalina/valves/LocalStrings_fr.properties
index ad9ad38..359f13d 100644
--- a/java/org/apache/catalina/valves/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/valves/LocalStrings_fr.properties
@@ -30,45 +30,45 @@ errorReportValve.note=note
 errorReportValve.rootCauseInLogs=La trace compl\u00e8te de la cause m\u00e8re de cette erreur est disponible dans les fichiers journaux de {0}.
 
 # HTTP status reports
-http.100=Le client peut continuer ({0}).
-http.101=Le serveur change de protocoles suivant la directive "Upgrade" de l''ent\u00eate ({0}).
-http.201=La requ\u00eate a r\u00e9ussi et une nouvelle ressource ({0}) a \u00e9t\u00e9 cr\u00e9\u00e9e sur le serveur.
-http.202=La requ\u00eate a \u00e9t\u00e9 accept\u00e9e pour traitement, mais n''a pas \u00e9t\u00e9 termin\u00e9e ({0}).
-http.203=L''information meta pr\u00e9sent\u00e9e par le client n''a pas pour origine ce serveur ({0}).
-http.204=La requ\u00eate a r\u00e9ussi mais il n''y a aucune information \u00e0 retourner ({0}).
-http.205=Le client doit remettre \u00e0 z\u00e9ro la vue de document qui a caus\u00e9 l''envoi de cette requ\u00eate ({0}).
-http.206=Le serveur a satisfait une requ\u00eate GET partielle pour cette ressource ({0}).
-http.207=Plusieurs valeurs d''\u00e9tats ont \u00e9t\u00e9 retourn\u00e9es ({0}).
-http.300=La ressource demand\u00e9e ({0}) correspond \u00e0 plusieurs repr\u00e9sentations, chacune avec sa propre localisation.
-http.301=La ressource demand\u00e9e ({0}) a \u00e9t\u00e9 d\u00e9plac\u00e9e de fa\u00e7on permanente vers une nouvelle localisation.
-http.302=La ressource demand\u00e9e ({0}) a \u00e9t\u00e9 d\u00e9plac\u00e9e de fa\u00e7on temporaire vers une nouvelle localisation.
-http.303=La r\u00e9ponse \u00e0 cette requ\u00eate peut \u00eatre trouv\u00e9e \u00e0 une URI diff\u00e9rente ({0}).
-http.304=La ressource demand\u00e9e ({0}) est disponible et n''a pas \u00e9t\u00e9 modifi\u00e9e.
-http.305=La ressource demand\u00e9e ({0}) doit \u00eatre acc\u00e9d\u00e9e au travers du relais indiqu\u00e9 par la directive "Location" de l''ent\u00eate.
-http.400=La requ\u00eate envoy\u00e9e par le client \u00e9tait syntaxiquement incorrecte ({0}).
-http.401=La requ\u00eate n\u00e9cessite une authentification HTTP ({0}).
-http.402=Un paiement est demand\u00e9 pour acc\u00e9der \u00e0 cette ressource ({0}).
-http.403=L''acc\u00e8s \u00e0 la ressource demand\u00e9e ({0}) a \u00e9t\u00e9 interdit.
-http.404=La ressource demand\u00e9e ({0}) n''est pas disponible.
-http.405=La m\u00e9thode HTTP sp\u00e9cifi\u00e9e n''est pas autoris\u00e9e pour la ressource demand\u00e9e ({0}).
-http.406=La ressource identifi\u00e9e par cette requ\u00eate n''est capable de g\u00e9n\u00e9rer des r\u00e9ponses qu''avec des caract\u00e9ristiques incompatible avec la directive "accept" pr\u00e9sente dans l''ent\u00eate de requ\u00eate ({0}).
-http.407=Le client doit d''abord s''authentifier aupr\u00e8s du relais ({0}).
-http.408=Le client n''a pas produit de requ\u00eate pendant le temps d''attente du serveur ({0}).
-http.409=La requ\u00eate ne peut \u00eatre finalis\u00e9e suite \u00e0 un conflit li\u00e9 \u00e0 l''\u00e9tat de la ressource ({0}).
-http.410=La ressource demand\u00e9e ({0}) n''est pas disponible, et aucune addresse de rebond (forwarding) n''est connue.
-http.411=La requ\u00eate ne peut \u00eatre trait\u00e9e sans d\u00e9finition d''une taille de contenu (content length) ({0}).
-http.412=Une condition pr\u00e9alable demand\u00e9e n''est pas satisfaite pour cette requ\u00eate ({0}).
+http.100=Le client peut continuer.
+http.101=Le serveur change de protocoles suivant la directive "Upgrade" de l''ent\u00eate.
+http.201=La requ\u00eate a r\u00e9ussi et une nouvelle ressource a \u00e9t\u00e9 cr\u00e9\u00e9e sur le serveur.
+http.202=La requ\u00eate a \u00e9t\u00e9 accept\u00e9e pour traitement, mais n''a pas \u00e9t\u00e9 termin\u00e9e.
+http.203=L''information meta pr\u00e9sent\u00e9e par le client n''a pas pour origine ce serveur.
+http.204=La requ\u00eate a r\u00e9ussi mais il n''y a aucune information \u00e0 retourner.
+http.205=Le client doit remettre \u00e0 z\u00e9ro la vue de document qui a caus\u00e9 l''envoi de cette requ\u00eate.
+http.206=Le serveur a satisfait une requ\u00eate GET partielle pour cette ressource.
+http.207=Plusieurs valeurs d''\u00e9tats ont \u00e9t\u00e9 retourn\u00e9es.
+http.300=La ressource demand\u00e9e correspond \u00e0 plusieurs repr\u00e9sentations, chacune avec sa propre localisation.
+http.301=La ressource demand\u00e9e a \u00e9t\u00e9 d\u00e9plac\u00e9e de fa\u00e7on permanente vers une nouvelle localisation.
+http.302=La ressource demand\u00e9e a \u00e9t\u00e9 d\u00e9plac\u00e9e de fa\u00e7on temporaire vers une nouvelle localisation.
+http.303=La r\u00e9ponse \u00e0 cette requ\u00eate peut \u00eatre trouv\u00e9e \u00e0 une URI diff\u00e9rente.
+http.304=La ressource demand\u00e9e est disponible et n''a pas \u00e9t\u00e9 modifi\u00e9e.
+http.305=La ressource demand\u00e9e doit \u00eatre acc\u00e9d\u00e9e au travers du relais indiqu\u00e9 par la directive "Location" de l''ent\u00eate.
+http.400=La requ\u00eate envoy\u00e9e par le client \u00e9tait syntaxiquement incorrecte.
+http.401=La requ\u00eate n\u00e9cessite une authentification HTTP.
+http.402=Un paiement est demand\u00e9 pour acc\u00e9der \u00e0 cette ressource.
+http.403=L''acc\u00e8s \u00e0 la ressource demand\u00e9e a \u00e9t\u00e9 interdit.
+http.404=La ressource demand\u00e9e n''est pas disponible.
+http.405=La m\u00e9thode HTTP sp\u00e9cifi\u00e9e n''est pas autoris\u00e9e pour la ressource demand\u00e9e.
+http.406=La ressource identifi\u00e9e par cette requ\u00eate n''est capable de g\u00e9n\u00e9rer des r\u00e9ponses qu''avec des caract\u00e9ristiques incompatible avec la directive "accept" pr\u00e9sente dans l''ent\u00eate de requ\u00eate.
+http.407=Le client doit d''abord s''authentifier aupr\u00e8s du relais.
+http.408=Le client n''a pas produit de requ\u00eate pendant le temps d''attente du serveur.
+http.409=La requ\u00eate ne peut \u00eatre finalis\u00e9e suite \u00e0 un conflit li\u00e9 \u00e0 l''\u00e9tat de la ressource.
+http.410=La ressource demand\u00e9e n''est pas disponible, et aucune addresse de rebond (forwarding) n''est connue.
+http.411=La requ\u00eate ne peut \u00eatre trait\u00e9e sans d\u00e9finition d''une taille de contenu (content length).
+http.412=Une condition pr\u00e9alable demand\u00e9e n''est pas satisfaite pour cette requ\u00eate.
 http.413=L''entit\u00e9 de requ\u00eate est plus importante que ce que le serveur veut ou peut traiter.
-http.414=Le serveur a refus\u00e9 cette requ\u00eate car l''URI de requ\u00eate est trop longue ({0}).
-http.415=Le serveur a refus\u00e9 cette requ\u00eate car l''entit\u00e9 de requ\u00eate est dans un format non support\u00e9 par la ressource demand\u00e9e avec la m\u00e9thode sp\u00e9cifi\u00e9e ({0}).
-http.416=La plage d''octets demand\u00e9e (byte range) ne peut \u00eatre satisfaite ({0}).
-http.417=L''attente indiqu\u00e9e dans la directive "Expect" de l''ent\u00eate de requ\u00eate ({0}) ne peut \u00eatre satisfaite.
-http.422=Le serveur a compris le type de contenu (content type) ainsi que la syntaxe de la requ\u00eate mais a \u00e9t\u00e9 incapable de traiter les instructions contenues ({0}).
-http.423=La ressource source ou destination de la m\u00e9thode est verrouill\u00e9e ({0}).
-http.500=Le serveur a rencontr\u00e9 une erreur interne ({0}) qui l''a emp\u00each\u00e9 de satisfaire la requ\u00eate.
-http.501=Le serveur ne supporte pas la fonctionnalit\u00e9 demand\u00e9e pour satisfaire cette requ\u00eate ({0}).
-http.502=Le serveur a re\u00e7u une r\u00e9ponse invalide d''un serveur qu''il consultait en tant que relais ou passerelle ({0}).
-http.503=Le service demand\u00e9 ({0}) n''est pas disponible actuellement.
-http.504=Le serveur a re\u00e7u un d\u00e9passement de delai (timeout) d''un serveur amont qu''il consultait en tant que relais ou passerelle ({0}).
-http.505=Le serveur ne supporte pas la version demand\u00e9e du protocole HTTP ({0}).
-http.507=L''espace disponible est insuffisant pour enregistrer l''\u00e9tat de la ressource apr\u00e8s ex\u00e9cution de cette m\u00e9thode ({0}).
+http.414=Le serveur a refus\u00e9 cette requ\u00eate car l''URI de requ\u00eate est trop longue.
+http.415=Le serveur a refus\u00e9 cette requ\u00eate car l''entit\u00e9 de requ\u00eate est dans un format non support\u00e9 par la ressource demand\u00e9e avec la m\u00e9thode sp\u00e9cifi\u00e9e.
+http.416=La plage d''octets demand\u00e9e (byte range) ne peut \u00eatre satisfaite.
+http.417=L''attente indiqu\u00e9e dans la directive "Expect" de l''ent\u00eate de requ\u00eate ne peut \u00eatre satisfaite.
+http.422=Le serveur a compris le type de contenu (content type) ainsi que la syntaxe de la requ\u00eate mais a \u00e9t\u00e9 incapable de traiter les instructions contenues.
+http.423=La ressource source ou destination de la m\u00e9thode est verrouill\u00e9e.
+http.500=Le serveur a rencontr\u00e9 une erreur interne qui l''a emp\u00each\u00e9 de satisfaire la requ\u00eate.
+http.501=Le serveur ne supporte pas la fonctionnalit\u00e9 demand\u00e9e pour satisfaire cette requ\u00eate.
+http.502=Le serveur a re\u00e7u une r\u00e9ponse invalide d''un serveur qu''il consultait en tant que relais ou passerelle.
+http.503=Le service demand\u00e9 n''est pas disponible actuellement.
+http.504=Le serveur a re\u00e7u un d\u00e9passement de delai (timeout) d''un serveur amont qu''il consultait en tant que relais ou passerelle.
+http.505=Le serveur ne supporte pas la version demand\u00e9e du protocole HTTP.
+http.507=L''espace disponible est insuffisant pour enregistrer l''\u00e9tat de la ressource apr\u00e8s ex\u00e9cution de cette m\u00e9thode.
diff --git a/java/org/apache/catalina/valves/StuckThreadDetectionValve.java b/java/org/apache/catalina/valves/StuckThreadDetectionValve.java
index 8d6af6a..f9f2cb3 100644
--- a/java/org/apache/catalina/valves/StuckThreadDetectionValve.java
+++ b/java/org/apache/catalina/valves/StuckThreadDetectionValve.java
@@ -35,12 +35,8 @@ import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
- * This valve allows to detect requests that take a long time to process, which might
- * indicate that the thread that is processing it is stuck.
- * Based on code proposed by TomLu in Bugzilla entry #50306
- *
- * @author slaurent
- *
+ * This valve allows to detect requests that take a long time to process, which
+ * might indicate that the thread that is processing it is stuck.
  */
 public class StuckThreadDetectionValve extends ValveBase {
 
@@ -136,10 +132,14 @@ public class StuckThreadDetectionValve extends ValveBase {
         if (log.isWarnEnabled()) {
             String msg = sm.getString(
                 "stuckThreadDetectionValve.notifyStuckThreadDetected",
-                monitoredThread.getThread().getName(), Long.valueOf(activeTime),
+                monitoredThread.getThread().getName(),
+                Long.valueOf(activeTime),
                 monitoredThread.getStartTime(),
                 Integer.valueOf(numStuckThreads),
-                monitoredThread.getRequestUri(), Integer.valueOf(threshold));
+                monitoredThread.getRequestUri(),
+                Integer.valueOf(threshold),
+                String.valueOf(monitoredThread.getThread().getId())
+                );
             // msg += "\n" + getStackTraceAsString(trace);
             Throwable th = new Throwable();
             th.setStackTrace(monitoredThread.getThread().getStackTrace());
@@ -147,13 +147,15 @@ public class StuckThreadDetectionValve extends ValveBase {
         }
     }
 
-    private void notifyStuckThreadCompleted(String threadName,
-            long activeTime, int numStuckThreads) {
+    private void notifyStuckThreadCompleted(CompletedStuckThread thread,
+            int numStuckThreads) {
         if (log.isWarnEnabled()) {
             String msg = sm.getString(
                 "stuckThreadDetectionValve.notifyStuckThreadCompleted",
-                threadName, Long.valueOf(activeTime),
-                Integer.valueOf(numStuckThreads));
+                thread.getName(),
+                Long.valueOf(thread.getTotalActiveTime()),
+                Integer.valueOf(numStuckThreads),
+                String.valueOf(thread.getId()));
             // Since the "stuck thread notification" is warn, this should also
             // be warn
             log.warn(msg);
@@ -193,7 +195,7 @@ public class StuckThreadDetectionValve extends ValveBase {
             activeThreads.remove(key);
             if (monitoredThread.markAsDone() == MonitoredThreadState.STUCK) {
                 completedStuckThreadsQueue.add(
-                        new CompletedStuckThread(monitoredThread.getThread().getName(),
+                        new CompletedStuckThread(monitoredThread.getThread(),
                             monitoredThread.getActiveTimeInMillis()));
             }
         }
@@ -220,8 +222,7 @@ public class StuckThreadDetectionValve extends ValveBase {
             completedStuckThread != null; completedStuckThread = completedStuckThreadsQueue.poll()) {
 
             int numStuckThreads = stuckCount.decrementAndGet();
-            notifyStuckThreadCompleted(completedStuckThread.getName(),
-                    completedStuckThread.getTotalActiveTime(), numStuckThreads);
+            notifyStuckThreadCompleted(completedStuckThread, numStuckThreads);
         }
     }
 
@@ -240,6 +241,16 @@ public class StuckThreadDetectionValve extends ValveBase {
         return result;
     }
 
+    public String[] getStuckThreadNames() {
+        List<String> nameList = new ArrayList<String>();
+        for (MonitoredThread monitoredThread : activeThreads.values()) {
+            if (monitoredThread.isMarkedAsStuck()) {
+                nameList.add(monitoredThread.getThread().getName());
+            }
+        }
+        return nameList.toArray(new String[nameList.size()]);
+    }
+
     private static class MonitoredThread {
 
         /**
@@ -291,10 +302,12 @@ public class StuckThreadDetectionValve extends ValveBase {
     private static class CompletedStuckThread {
 
         private final String threadName;
+        private final long threadId;
         private final long totalActiveTime;
 
-        public CompletedStuckThread(String threadName, long totalActiveTime) {
-            this.threadName = threadName;
+        public CompletedStuckThread(Thread thread, long totalActiveTime) {
+            this.threadName = thread.getName();
+            this.threadId = thread.getId();
             this.totalActiveTime = totalActiveTime;
         }
 
@@ -302,6 +315,10 @@ public class StuckThreadDetectionValve extends ValveBase {
             return this.threadName;
         }
 
+        public long getId() {
+            return this.threadId;
+        }
+
         public long getTotalActiveTime() {
             return this.totalActiveTime;
         }
diff --git a/java/org/apache/catalina/valves/mbeans-descriptors.xml b/java/org/apache/catalina/valves/mbeans-descriptors.xml
index b132a01..654502f 100644
--- a/java/org/apache/catalina/valves/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/valves/mbeans-descriptors.xml
@@ -536,10 +536,15 @@
                writeable="false"/>
 
     <attribute name="stuckThreadIds"
-               description="IDs of the thread currently considered stuck. Each ID can then be used with the ThreadMXBean to retrieve data about it."
+               description="IDs of the threads currently considered stuck. Each ID can then be used with the Threading MBean to retrieve data about it."
                type="long[]"
                writeable="false"/>
 
+    <attribute name="stuckThreadNames"
+               description="Names of the threads currently considered stuck."
+               type="java.lang.String[]"
+               writeable="false"/>
+
     <attribute name="threshold"
                description="Duration in seconds after which a request is considered as stuck"
                type="int"/>
diff --git a/java/org/apache/catalina/websocket/LocalStrings.properties b/java/org/apache/catalina/websocket/LocalStrings.properties
index 5280614..7a497f6 100644
--- a/java/org/apache/catalina/websocket/LocalStrings.properties
+++ b/java/org/apache/catalina/websocket/LocalStrings.properties
@@ -26,4 +26,6 @@ message.bufferTooSmall=The buffer is not big enough to contain the message curre
 
 servlet.reqUpgradeFail=Unable to cast to the Tomcat internal request class in order to complete HTTP upgrade
 
-outbound.closed=The WebSocket connection has been closed
\ No newline at end of file
+outbound.closed=The WebSocket connection has been closed
+
+wrapper.invalid=An attempt was made to access the request object passed to WebSocketServlet.createWebSocketInbound() outside of that method
\ No newline at end of file
diff --git a/java/org/apache/catalina/websocket/StreamInbound.java b/java/org/apache/catalina/websocket/StreamInbound.java
index 8a34daf..87375ff 100644
--- a/java/org/apache/catalina/websocket/StreamInbound.java
+++ b/java/org/apache/catalina/websocket/StreamInbound.java
@@ -202,7 +202,7 @@ public abstract class StreamInbound implements UpgradeInbound {
         try {
             getWsOutbound().close(frame);
         } finally {
-            doOnClose(Constants.OPCODE_CLOSE);
+            doOnClose(Constants.STATUS_CLOSE_NORMAL);
         }
     }
 
diff --git a/java/org/apache/catalina/websocket/WebSocketServlet.java b/java/org/apache/catalina/websocket/WebSocketServlet.java
index 470fef2..5b37306 100644
--- a/java/org/apache/catalina/websocket/WebSocketServlet.java
+++ b/java/org/apache/catalina/websocket/WebSocketServlet.java
@@ -52,7 +52,7 @@ public abstract class WebSocketServlet extends HttpServlet {
     private static final StringManager sm =
             StringManager.getManager(Constants.Package);
 
-    private Queue<MessageDigest> sha1Helpers =
+    private final Queue<MessageDigest> sha1Helpers =
             new ConcurrentLinkedQueue<MessageDigest>();
 
 
@@ -94,7 +94,7 @@ public abstract class WebSocketServlet extends HttpServlet {
         }
 
         List<String> subProtocols = getTokensFromHeader(req,
-                "Sec-WebSocket-Protocol-Client");
+                "Sec-WebSocket-Protocol");
         if (!subProtocols.isEmpty()) {
             subProtocol = selectSubProtocol(subProtocols);
 
@@ -117,7 +117,9 @@ public abstract class WebSocketServlet extends HttpServlet {
             // TODO
         }
 
-        StreamInbound inbound = createWebSocketInbound(subProtocol);
+        WsHttpServletRequestWrapper wrapper = new WsHttpServletRequestWrapper(req);
+        StreamInbound inbound = createWebSocketInbound(subProtocol, wrapper);
+        wrapper.invalidate();
 
         // Small hack until the Servlet API provides a way to do this.
         ServletRequest inner = req;
@@ -234,6 +236,13 @@ public abstract class WebSocketServlet extends HttpServlet {
      *
      * @param subProtocol   The sub-protocol agreed between the client and
      *                      server or <code>null</code> if none was agreed
+     * @param request       The HTTP request that initiated this WebSocket
+     *                      connection. Note that this object is <b>only</b>
+     *                      valid inside this method. You must not retain a
+     *                      reference to it outside the execution of this
+     *                      method. If Tomcat detects such access, it will throw
+     *                      an IllegalStateException
      */
-    protected abstract StreamInbound createWebSocketInbound(String subProtocol);
+    protected abstract StreamInbound createWebSocketInbound(String subProtocol,
+            HttpServletRequest request);
 }
diff --git a/java/org/apache/catalina/websocket/WsFrame.java b/java/org/apache/catalina/websocket/WsFrame.java
index a79f3ce..7cdc14e 100644
--- a/java/org/apache/catalina/websocket/WsFrame.java
+++ b/java/org/apache/catalina/websocket/WsFrame.java
@@ -39,9 +39,9 @@ public class WsFrame {
     private final boolean fin;
     private final int rsv;
     private final byte opCode;
-    private byte[] mask = new byte[4];
+    private final byte[] mask = new byte[4];
     private long payloadLength;
-    private ByteBuffer payload;
+    private final ByteBuffer payload;
 
     /**
      * Create the new WebSocket frame, reading data from the processor as
diff --git a/java/org/apache/catalina/websocket/WsHttpServletRequestWrapper.java b/java/org/apache/catalina/websocket/WsHttpServletRequestWrapper.java
new file mode 100644
index 0000000..a06f1e3
--- /dev/null
+++ b/java/org/apache/catalina/websocket/WsHttpServletRequestWrapper.java
@@ -0,0 +1,404 @@
+/*
+ * 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.websocket;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
+
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * Wrapper for the HttpServletRequest object that allows the underlying request
+ * object to be invalidated.
+ */
+public class WsHttpServletRequestWrapper implements HttpServletRequest {
+
+    private static final StringManager sm =
+            StringManager.getManager(Constants.Package);
+
+    private HttpServletRequest request;
+
+    public WsHttpServletRequestWrapper(HttpServletRequest request) {
+        this.request = request;
+    }
+
+    private HttpServletRequest getRequest() {
+        if (request == null) {
+            throw new IllegalStateException(sm.getString("wrapper.invalid"));
+        }
+        return request;
+    }
+
+    protected void invalidate() {
+        request = null;
+    }
+
+    @Override
+    public Object getAttribute(String name) {
+        return getRequest().getAttribute(name);
+    }
+
+    @Override
+    public Enumeration<String> getAttributeNames() {
+        return getRequest().getAttributeNames();
+    }
+
+    @Override
+    public String getCharacterEncoding() {
+        return getRequest().getCharacterEncoding();
+    }
+
+    @Override
+    public void setCharacterEncoding(String env)
+            throws UnsupportedEncodingException {
+        getRequest().setCharacterEncoding(env);
+    }
+
+    @Override
+    public int getContentLength() {
+        return getRequest().getContentLength();
+    }
+
+    @Override
+    public String getContentType() {
+        return getRequest().getContentType();
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException {
+        return getRequest().getInputStream();
+    }
+
+    @Override
+    public String getParameter(String name) {
+        return getRequest().getParameter(name);
+    }
+
+    @Override
+    public Enumeration<String> getParameterNames() {
+        return getRequest().getParameterNames();
+    }
+
+    @Override
+    public String[] getParameterValues(String name) {
+        return getRequest().getParameterValues(name);
+    }
+
+    @Override
+    public Map<String, String[]> getParameterMap() {
+        return getRequest().getParameterMap();
+    }
+
+    @Override
+    public String getProtocol() {
+        return getRequest().getProtocol();
+    }
+
+    @Override
+    public String getScheme() {
+        return getRequest().getScheme();
+    }
+
+    @Override
+    public String getServerName() {
+        return getRequest().getServerName();
+    }
+
+    @Override
+    public int getServerPort() {
+        return getRequest().getServerPort();
+    }
+
+    @Override
+    public BufferedReader getReader() throws IOException {
+        return getRequest().getReader();
+    }
+
+    @Override
+    public String getRemoteAddr() {
+        return getRequest().getRemoteAddr();
+    }
+
+    @Override
+    public String getRemoteHost() {
+        return getRequest().getRemoteHost();
+    }
+
+    @Override
+    public void setAttribute(String name, Object o) {
+        getRequest().setAttribute(name, o);
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        getRequest().removeAttribute(name);
+    }
+
+    @Override
+    public Locale getLocale() {
+        return getRequest().getLocale();
+    }
+
+    @Override
+    public Enumeration<Locale> getLocales() {
+        return getRequest().getLocales();
+    }
+
+    @Override
+    public boolean isSecure() {
+        return getRequest().isSecure();
+    }
+
+    @Override
+    public RequestDispatcher getRequestDispatcher(String path) {
+        return getRequest().getRequestDispatcher(path);
+    }
+
+    @Override
+    @Deprecated
+    public String getRealPath(String path) {
+        return getRequest().getRealPath(path);
+    }
+
+    @Override
+    public int getRemotePort() {
+        return getRequest().getRemotePort();
+    }
+
+    @Override
+    public String getLocalName() {
+        return getRequest().getLocalName();
+    }
+
+    @Override
+    public String getLocalAddr() {
+        return getRequest().getLocalAddr();
+    }
+
+    @Override
+    public int getLocalPort() {
+        return getRequest().getLocalPort();
+    }
+
+    @Override
+    public ServletContext getServletContext() {
+        return getRequest().getServletContext();
+    }
+
+    @Override
+    public AsyncContext startAsync() throws IllegalStateException {
+        return getRequest().startAsync();
+    }
+
+    @Override
+    public AsyncContext startAsync(ServletRequest servletRequest,
+            ServletResponse servletResponse) throws IllegalStateException {
+        return getRequest().startAsync(servletRequest, servletResponse);
+    }
+
+    @Override
+    public boolean isAsyncStarted() {
+        return getRequest().isAsyncStarted();
+    }
+
+    @Override
+    public boolean isAsyncSupported() {
+        return getRequest().isAsyncSupported();
+    }
+
+    @Override
+    public AsyncContext getAsyncContext() {
+        return getRequest().getAsyncContext();
+    }
+
+    @Override
+    public DispatcherType getDispatcherType() {
+        return getRequest().getDispatcherType();
+    }
+
+    @Override
+    public String getAuthType() {
+        return getRequest().getAuthType();
+    }
+
+    @Override
+    public Cookie[] getCookies() {
+        return getRequest().getCookies();
+    }
+
+    @Override
+    public long getDateHeader(String name) {
+        return getRequest().getDateHeader(name);
+    }
+
+    @Override
+    public String getHeader(String name) {
+        return getRequest().getHeader(name);
+    }
+
+    @Override
+    public Enumeration<String> getHeaders(String name) {
+        return getRequest().getHeaders(name);
+    }
+
+    @Override
+    public Enumeration<String> getHeaderNames() {
+        return getRequest().getHeaderNames();
+    }
+
+    @Override
+    public int getIntHeader(String name) {
+        return getRequest().getIntHeader(name);
+    }
+
+    @Override
+    public String getMethod() {
+        return getRequest().getMethod();
+    }
+
+    @Override
+    public String getPathInfo() {
+        return getRequest().getPathInfo();
+    }
+
+    @Override
+    public String getPathTranslated() {
+        return getRequest().getPathTranslated();
+    }
+
+    @Override
+    public String getContextPath() {
+        return getRequest().getContextPath();
+    }
+
+    @Override
+    public String getQueryString() {
+        return getRequest().getQueryString();
+    }
+
+    @Override
+    public String getRemoteUser() {
+        return getRequest().getRemoteUser();
+    }
+
+    @Override
+    public boolean isUserInRole(String role) {
+        return getRequest().isUserInRole(role);
+    }
+
+    @Override
+    public Principal getUserPrincipal() {
+        return getRequest().getUserPrincipal();
+    }
+
+    @Override
+    public String getRequestedSessionId() {
+        return getRequest().getRequestedSessionId();
+    }
+
+    @Override
+    public String getRequestURI() {
+        return getRequest().getRequestURI();
+    }
+
+    @Override
+    public StringBuffer getRequestURL() {
+        return getRequest().getRequestURL();
+    }
+
+    @Override
+    public String getServletPath() {
+        return getRequest().getServletPath();
+    }
+
+    @Override
+    public HttpSession getSession(boolean create) {
+        return getRequest().getSession(create);
+    }
+
+    @Override
+    public HttpSession getSession() {
+        return getRequest().getSession();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdValid() {
+        return getRequest().isRequestedSessionIdValid();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromCookie() {
+        return getRequest().isRequestedSessionIdFromCookie();
+    }
+
+    @Override
+    public boolean isRequestedSessionIdFromURL() {
+        return getRequest().isRequestedSessionIdFromURL();
+    }
+
+    @Override
+    @Deprecated
+    public boolean isRequestedSessionIdFromUrl() {
+        return getRequest().isRequestedSessionIdFromUrl();
+    }
+
+    @Override
+    public boolean authenticate(HttpServletResponse response)
+            throws IOException, ServletException {
+        return getRequest().authenticate(response);
+    }
+
+    @Override
+    public void login(String username, String password) throws ServletException {
+        getRequest().login(username, password);
+    }
+
+    @Override
+    public void logout() throws ServletException {
+        getRequest().logout();
+    }
+
+    @Override
+    public Collection<Part> getParts() throws IOException, ServletException {
+        return getRequest().getParts();
+    }
+
+    @Override
+    public Part getPart(String name) throws IOException, ServletException {
+        return getRequest().getPart(name);
+    }
+}
diff --git a/java/org/apache/catalina/websocket/WsInputStream.java b/java/org/apache/catalina/websocket/WsInputStream.java
index 89b3363..af077e2 100644
--- a/java/org/apache/catalina/websocket/WsInputStream.java
+++ b/java/org/apache/catalina/websocket/WsInputStream.java
@@ -34,8 +34,8 @@ public class WsInputStream extends InputStream {
             StringManager.getManager(Constants.Package);
 
 
-    private UpgradeProcessor<?> processor;
-    private WsOutbound outbound;
+    private final UpgradeProcessor<?> processor;
+    private final WsOutbound outbound;
 
     private WsFrame frame;
     private long remaining;
diff --git a/java/org/apache/catalina/websocket/WsOutbound.java b/java/org/apache/catalina/websocket/WsOutbound.java
index ae4285d..2f3ef07 100644
--- a/java/org/apache/catalina/websocket/WsOutbound.java
+++ b/java/org/apache/catalina/websocket/WsOutbound.java
@@ -301,6 +301,29 @@ public class WsOutbound {
      * @throws IOException  If an error occurs writing to the client
      */
     public synchronized void pong(ByteBuffer data) throws IOException {
+        sendControlMessage(data, Constants.OPCODE_PONG);
+    }
+
+    /**
+     * Send a ping message to the client
+     *
+     * @param data      Optional message.
+     *
+     * @throws IOException  If an error occurs writing to the client
+     */
+    public synchronized void ping(ByteBuffer data) throws IOException {
+        sendControlMessage(data, Constants.OPCODE_PING);
+    }
+
+    /**
+     * Generic function to send either a ping or a pong.
+     *
+     * @param data      Optional message.
+     * @param opcode    The byte to include as the opcode.
+     *
+     * @throws IOException  If an error occurs writing to the client
+     */
+    private synchronized void sendControlMessage(ByteBuffer data, byte opcode) throws IOException {
 
         if (closed) {
             throw new IOException(sm.getString("outbound.closed"));
@@ -308,7 +331,7 @@ public class WsOutbound {
 
         doFlush(true);
 
-        upgradeOutbound.write(0x8A);
+        upgradeOutbound.write(0x80 | opcode);
         if (data == null) {
             upgradeOutbound.write(0);
         } else {
diff --git a/java/org/apache/coyote/AbstractProtocol.java b/java/org/apache/coyote/AbstractProtocol.java
index e86eff8..c079a48 100644
--- a/java/org/apache/coyote/AbstractProtocol.java
+++ b/java/org/apache/coyote/AbstractProtocol.java
@@ -149,6 +149,12 @@ public abstract class AbstractProtocol implements ProtocolHandler,
     public void setClientCertProvider(String s) { this.clientCertProvider = s; }
 
 
+    @Override
+    public boolean isAprRequired() {
+        return false;
+    }
+
+
     // ---------------------- Properties that are passed through to the EndPoint
 
     @Override
@@ -567,9 +573,13 @@ public abstract class AbstractProtocol implements ProtocolHandler,
 
                 SocketState state = SocketState.CLOSED;
                 do {
-                    if (status == SocketStatus.DISCONNECT) {
-                        //do nothing here, just wait for it to get recycled
-                    } else if (processor.isAsync() || state == SocketState.ASYNC_END) {
+                    if (status == SocketStatus.DISCONNECT &&
+                            !processor.isComet()) {
+                        // Do nothing here, just wait for it to get recycled
+                        // Don't do this for Comet we need to generate an end
+                        // event (see BZ 54022)
+                    } else if (processor.isAsync() ||
+                            state == SocketState.ASYNC_END) {
                         state = processor.asyncDispatch(status);
                     } else if (processor.isComet()) {
                         state = processor.event(status);
@@ -622,11 +632,11 @@ public abstract class AbstractProtocol implements ProtocolHandler,
             } catch(java.net.SocketException e) {
                 // SocketExceptions are normal
                 getLog().debug(sm.getString(
-                        "ajpprotocol.proto.socketexception.debug"), e);
+                        "abstractConnectionHandler.socketexception.debug"), e);
             } catch (java.io.IOException e) {
                 // IOExceptions are normal
                 getLog().debug(sm.getString(
-                        "ajpprotocol.proto.ioexception.debug"), e);
+                        "abstractConnectionHandler.ioexception.debug"), e);
             }
             // Future developers: if you discover any other
             // rare-but-nonfatal exceptions, catch them here, and log as
@@ -636,7 +646,8 @@ public abstract class AbstractProtocol implements ProtocolHandler,
                 // any other exception or error is odd. Here we log it
                 // with "ERROR" level, so it will show up even on
                 // less-than-verbose logs.
-                getLog().error(sm.getString("ajpprotocol.proto.error"), e);
+                getLog().error(
+                        sm.getString("abstractConnectionHandler.error"), e);
             }
             // Don't try to add upgrade processors back into the pool
             if (!(processor instanceof UpgradeProcessor)) {
diff --git a/java/org/apache/coyote/ActionCode.java b/java/org/apache/coyote/ActionCode.java
index 9131838..0f3fbce 100644
--- a/java/org/apache/coyote/ActionCode.java
+++ b/java/org/apache/coyote/ActionCode.java
@@ -192,6 +192,11 @@ public enum ActionCode {
     ASYNC_IS_TIMINGOUT,
 
     /**
+    * Callback to determine if async is in error
+    */
+    ASYNC_IS_ERROR,
+
+    /**
      * Callback to trigger the HTTP upgrade process.
      */
     UPGRADE
diff --git a/java/org/apache/coyote/AsyncStateMachine.java b/java/org/apache/coyote/AsyncStateMachine.java
index c4d5b1f..d86d12d 100644
--- a/java/org/apache/coyote/AsyncStateMachine.java
+++ b/java/org/apache/coyote/AsyncStateMachine.java
@@ -49,40 +49,46 @@ import org.apache.tomcat.util.res.StringManager;
  * DISPATCHING   - The dispatch is being processed.
  * ERROR         - Something went wrong.
  *
- * |----------------->--------------|                                         
- * |                               \|/                                        
- * |   |----------<---------------ERROR                                    
- * |   |    complete()           /|\ |postProcess()
- * |   |                   error()|  |
- * |   |                          |  |  |--|timeout()
- * |   |           postProcess()  | \|/ | \|/            auto
- * |   |         |--------------->DISPATCHED<------------------COMPLETING<----|
- * |   |         |               /|\  |                          | /|\        | 
- * |   |         |    |--->-------|   |                          |--|         | 
- * |   |         ^    |               |startAsync()            timeout()      |
- * |   |         |    |               |                                       | 
- * |  \|/        |    |  complete()  \|/        postProcess()                 | 
- * | MUST_COMPLETE-<- | ----<------STARTING-->----------------|               ^     
- * |      /|\         |               |                       |               |         
- * |       |          |               |                       |               |         
- * |       |          ^               |dispatch()             |               |         
- * |       |          |               |                       |               |         
- * |       |          |              \|/                     \|/   complete() |         
- * |       |          |         MUST_DISPATCH              STARTED---->-------|   
- * |       |          |           |                         |   |                        
- * |       |          |           |postProcess()            |   |                        
- * ^       ^          |           |              dispatch() |   |auto                        
- * |       |          |           |    |--------------------|   |                        
- * |       |          | auto     \|/  \|/                      \|/                         
- * |       |          |---<----DISPATCHING<-----------------TIMING_OUT                              
- * |       |                                  dispatch()      |   |             
- * |       |                                                  |   |            
- * |       |-------<-------------------------------------<----|   |            
- * |                              complete()                      |            
- * |                                                              |            
- * |----<------------------------<-----------------------------<--|            
- *                                 error()
- * </pre>                               
+ * |----------------->--------------|
+ * |                               \|/
+ * |   |----------<---------------ERROR
+ * |   |      complete()         /|\ | \                                                          
+ * |   |                          |  |  \---------------|                                         
+ * |   |                          |  |                  |dispatch()                               
+ * |   |                          |  |postProcess()    \|/                                        
+ * |   |                   error()|  |                  |                                         
+ * |   |                          |  |  |--|timeout()   |                                         
+ * |   |           postProcess()  | \|/ | \|/           |         auto                            
+ * |   |         |--------------->DISPATCHED<---------- | --------------COMPLETING<-----|         
+ * |   |         |               /|\  |                 |                 | /|\         |         
+ * |   |         |    |--->-------|   |                 |                 |--|          |         
+ * |   |         ^    |               |startAsync()     |               timeout()       |         
+ * |   |         |    |               |                 |                               |         
+ * |  \|/        |    |  complete()  \|/  postProcess() |                               |         
+ * | MUST_COMPLETE-<- | ----<------STARTING-->--------- | ------------|                 ^         
+ * |         /|\      |               |                 |             |      complete() |         
+ * |          |       |               |                 |             |     /-----------|         
+ * |          |       ^               |dispatch()       |             |    /                      
+ * |          |       |               |                 |             |   /                       
+ * |          |       |              \|/                /            \|/ /                        
+ * |          |       |         MUST_DISPATCH          /           STARTED
+ * |          |       |           |                   /            /|  
+ * |          |       |           |postProcess()     /            / |   
+ * ^          ^       |           |                 /  dispatch()/  |    
+ * |          |       |           |                /            /   |    
+ * |          |       |           |   |---------- / -----------/    |auto
+ * |          |       |           |   |          /                  |   
+ * |          |       |           |   |   |-----/                   |   
+ * |          |       | auto     \|/ \|/ \|/                       \|/  
+ * |          |       |---<------DISPATCHING<-----------------TIMING_OUT
+ * |          |                               dispatch()        |   |
+ * |          |                                                 |   |
+ * |          |-------<----------------------------------<------|   |
+ * |                              complete()                        |  
+ * |                                                                |  
+ * |<--------<-------------------<-------------------------------<--|  
+ *                                 error()                             
+ * </pre>
  */
 public class AsyncStateMachine<S> {
 
@@ -99,7 +105,7 @@ public class AsyncStateMachine<S> {
         MUST_COMPLETE(true, false, false),
         COMPLETING(true, false, false),
         TIMING_OUT(true, false, false),
-        MUST_DISPATCH(true, false, true),
+        MUST_DISPATCH(true, true, true),
         DISPATCHING(true, false, true),
         ERROR(true,false,false);
     
@@ -155,6 +161,9 @@ public class AsyncStateMachine<S> {
         return state == AsyncState.TIMING_OUT;
     }
 
+    public boolean isAsyncError() {
+        return state == AsyncState.ERROR;
+    }
 
     public synchronized void asyncStart(AsyncContextCallback asyncCtxt) {
         if (state == AsyncState.DISPATCHED) {
@@ -191,13 +200,6 @@ public class AsyncStateMachine<S> {
         } else if (state == AsyncState.DISPATCHING) {
             state = AsyncState.DISPATCHED;
             return SocketState.ASYNC_END;
-        } else if (state == AsyncState.ERROR) {
-            asyncCtxt.fireOnComplete();
-            state = AsyncState.DISPATCHED;
-            return SocketState.ASYNC_END;
-        //} else if (state == AsyncState.DISPATCHED) {
-        //    // No state change
-        //    return SocketState.OPEN;
         } else {
             throw new IllegalStateException(
                     sm.getString("asyncStateMachine.invalidAsyncState",
@@ -249,7 +251,8 @@ public class AsyncStateMachine<S> {
         if (state == AsyncState.STARTING) {
             state = AsyncState.MUST_DISPATCH;
         } else if (state == AsyncState.STARTED ||
-                state == AsyncState.TIMING_OUT) {
+                state == AsyncState.TIMING_OUT ||
+                state == AsyncState.ERROR) {
             state = AsyncState.DISPATCHING;
             doDispatch = true;
         } else {
diff --git a/java/org/apache/coyote/LocalStrings.properties b/java/org/apache/coyote/LocalStrings.properties
index 94a44ad..a9a4c34 100644
--- a/java/org/apache/coyote/LocalStrings.properties
+++ b/java/org/apache/coyote/LocalStrings.properties
@@ -12,6 +12,9 @@
 # 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.
+abstractConnectionHandler.error=Error reading request, ignored
+abstractConnectionHandler.ioexception.debug=IOExceptions are normal, ignored
+abstractConnectionHandler.socketexception.debug=SocketExceptions are normal, ignored
 
 abstractProtocolHandler.getAttribute=Get attribute [{0}] with value [{1}]
 abstractProtocolHandler.setAttribute=Set attribute [{0}] with value [{1}]
diff --git a/java/org/apache/coyote/LocalStrings_es.properties b/java/org/apache/coyote/LocalStrings_es.properties
new file mode 100644
index 0000000..477d970
--- /dev/null
+++ b/java/org/apache/coyote/LocalStrings_es.properties
@@ -0,0 +1,15 @@
+# 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.
+abstractConnectionHandler.error = Error leyendo requerimiento, ignorado
diff --git a/java/org/apache/coyote/ProtocolHandler.java b/java/org/apache/coyote/ProtocolHandler.java
index b1594c8..344d406 100644
--- a/java/org/apache/coyote/ProtocolHandler.java
+++ b/java/org/apache/coyote/ProtocolHandler.java
@@ -82,4 +82,10 @@ public interface ProtocolHandler {
      * Destroy the protocol (optional).
      */
     public void destroy() throws Exception;
+
+
+    /**
+     * Requires APR/native library
+     */
+    public boolean isAprRequired();
 }
diff --git a/java/org/apache/coyote/Response.java b/java/org/apache/coyote/Response.java
index df35070..ad32b70 100644
--- a/java/org/apache/coyote/Response.java
+++ b/java/org/apache/coyote/Response.java
@@ -23,9 +23,8 @@ import java.util.Locale;
 
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.http.MimeHeaders;
-import org.apache.tomcat.util.http.parser.AstMediaType;
 import org.apache.tomcat.util.http.parser.HttpParser;
-import org.apache.tomcat.util.http.parser.ParseException;
+import org.apache.tomcat.util.http.parser.MediaType;
 
 /**
  * Response object.
@@ -435,11 +434,13 @@ public final class Response {
             return;
         }
 
-        AstMediaType m = null;
-        HttpParser hp = new HttpParser(new StringReader(type));
+        MediaType m = null;
         try {
-             m = hp.MediaType();
-        } catch (ParseException e) {
+             m = HttpParser.parseMediaType(new StringReader(type));
+        } catch (IOException e) {
+            // Ignore - null test below handles this
+        }
+        if (m == null) {
             // Invalid - Assume no charset and just pass through whatever
             // the user provided.
             this.contentType = type;
diff --git a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
index 374c3e0..5ecbb38 100644
--- a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
+++ b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
@@ -457,6 +457,8 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> {
             ((AtomicBoolean) param).set(asyncStateMachine.isAsync());
         } else if (actionCode == ActionCode.ASYNC_IS_TIMINGOUT) {
             ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut());
+        } else if (actionCode == ActionCode.ASYNC_IS_ERROR) {
+            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncError());
         } else if (actionCode == ActionCode.UPGRADE) {
             // HTTP connections only. Unsupported for AJP.
             // NOOP
diff --git a/java/org/apache/coyote/ajp/AjpAprProcessor.java b/java/org/apache/coyote/ajp/AjpAprProcessor.java
index 2e758f3..e609281 100644
--- a/java/org/apache/coyote/ajp/AjpAprProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpAprProcessor.java
@@ -319,7 +319,7 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
             if (nRead > 0) {
                 inputBuffer.limit(inputBuffer.limit() + nRead);
             } else {
-                throw new IOException(sm.getString("ajpprotocol.failedread"));
+                throw new IOException(sm.getString("ajpprocessor.failedread"));
             }
         }
 
@@ -355,7 +355,7 @@ public class AjpAprProcessor extends AbstractAjpProcessor<Long> {
                 if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) {
                     return false;
                 } else {
-                    throw new IOException(sm.getString("ajpprotocol.failedread"));
+                    throw new IOException(sm.getString("ajpprocessor.failedread"));
                 }
             }
         }
diff --git a/java/org/apache/coyote/ajp/AjpAprProtocol.java b/java/org/apache/coyote/ajp/AjpAprProtocol.java
index 4e3ce0c..947e8f6 100644
--- a/java/org/apache/coyote/ajp/AjpAprProtocol.java
+++ b/java/org/apache/coyote/ajp/AjpAprProtocol.java
@@ -49,9 +49,16 @@ public class AjpAprProtocol extends AbstractAjpProtocol {
     }
 
 
-    // ------------------------------------------------------------ Constructor
+    @Override
+    public boolean isAprRequired() {
+        // Override since this protocol implementation requires the APR/native
+        // library
+        return true;
+    }
 
 
+    // ------------------------------------------------------------ Constructor
+
     public AjpAprProtocol() {
         endpoint = new AprEndpoint();
         cHandler = new AjpConnectionHandler(this);
@@ -128,7 +135,8 @@ public class AjpAprProtocol extends AbstractAjpProtocol {
             if (addToPoller) {
                 ((AprEndpoint)proto.endpoint).getPoller().add(
                         socket.getSocket().longValue(),
-                        proto.endpoint.getKeepAliveTimeout());
+                        proto.endpoint.getKeepAliveTimeout(),
+                        AprEndpoint.Poller.FLAGS_READ);
             }
         }
 
diff --git a/java/org/apache/coyote/ajp/AjpMessage.java b/java/org/apache/coyote/ajp/AjpMessage.java
index 5b64a15..87a0353 100644
--- a/java/org/apache/coyote/ajp/AjpMessage.java
+++ b/java/org/apache/coyote/ajp/AjpMessage.java
@@ -355,7 +355,7 @@ public class AjpMessage {
 
 
     public int getHeaderLength() {
-        return 4;
+        return Constants.H_SIZE;
     }
 
     
diff --git a/java/org/apache/coyote/ajp/AjpNioProcessor.java b/java/org/apache/coyote/ajp/AjpNioProcessor.java
index f0ddbc3..5966f40 100644
--- a/java/org/apache/coyote/ajp/AjpNioProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpNioProcessor.java
@@ -317,7 +317,7 @@ public class AjpNioProcessor extends AbstractAjpProcessor<NioChannel> {
             } else if (res == 0 && !block) {
                 break;
             } else {
-                throw new IOException(sm.getString("ajpprotocol.failedread"));
+                throw new IOException(sm.getString("ajpprocessor.failedread"));
             }
             block = true;
         }
diff --git a/java/org/apache/coyote/ajp/AjpProcessor.java b/java/org/apache/coyote/ajp/AjpProcessor.java
index 5998989..95769c3 100644
--- a/java/org/apache/coyote/ajp/AjpProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpProcessor.java
@@ -310,7 +310,7 @@ public class AjpProcessor extends AbstractAjpProcessor<Socket> {
             if (res > 0) {
                 read += res;
             } else {
-                throw new IOException(sm.getString("ajpprotocol.failedread"));
+                throw new IOException(sm.getString("ajpprocessor.failedread"));
             }
         }
         
diff --git a/java/org/apache/coyote/ajp/Constants.java b/java/org/apache/coyote/ajp/Constants.java
index 49c95a7..27f1448 100644
--- a/java/org/apache/coyote/ajp/Constants.java
+++ b/java/org/apache/coyote/ajp/Constants.java
@@ -40,14 +40,22 @@ public final class Constants {
 
     public static final int DEFAULT_CONNECTION_LINGER = -1;
     public static final int DEFAULT_CONNECTION_TIMEOUT = -1;
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000;
     public static final boolean DEFAULT_TCP_NO_DELAY = true;
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final boolean DEFAULT_USE_SENDFILE = false;
 
     // Prefix codes for message types from server to container
     public static final byte JK_AJP13_FORWARD_REQUEST   = 2;
-    public static final byte JK_AJP13_SHUTDOWN          = 7;
-    public static final byte JK_AJP13_PING_REQUEST      = 8;
+    public static final byte JK_AJP13_SHUTDOWN          = 7;    // XXX Unused
+    public static final byte JK_AJP13_PING_REQUEST      = 8;    // XXX Unused
     public static final byte JK_AJP13_CPING_REQUEST     = 10;
 
     // Prefix codes for message types from container to server
@@ -81,7 +89,12 @@ public final class Constants {
     public static final byte SC_A_SSL_CERT      = 7;
     public static final byte SC_A_SSL_CIPHER    = 8;
     public static final byte SC_A_SSL_SESSION   = 9;
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte SC_A_SSL_KEYSIZE   = 11;
+    public static final byte SC_A_SSL_KEY_SIZE  = 11;
     public static final byte SC_A_SECRET        = 12;
     public static final byte SC_A_STORED_METHOD = 13;
 
@@ -176,8 +189,6 @@ public final class Constants {
     public static final int SC_REQ_PRAGMA          = 12;
     public static final int SC_REQ_REFERER         = 13;
     public static final int SC_REQ_USER_AGENT      = 14;
-    // AJP14 new header
-    public static final byte SC_A_SSL_KEY_SIZE  = 11; // XXX ???
 
     // Translates integer codes to request header names
     private static final String [] headerTransArray = {
@@ -258,164 +269,266 @@ public final class Constants {
     
     /**
      * CRLF.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final String CRLF = "\r\n";
 
 
     /**
      * Server string.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte[] SERVER_BYTES =
         ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF);
 
 
     /**
      * CR.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte CR = (byte) '\r';
 
 
     /**
      * LF.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte LF = (byte) '\n';
 
 
     /**
      * SP.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte SP = (byte) ' ';
 
 
     /**
      * HT.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte HT = (byte) '\t';
 
 
     /**
      * COLON.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte COLON = (byte) ':';
 
 
     /**
      * 'A'.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte A = (byte) 'A';
 
 
     /**
      * 'a'.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte a = (byte) 'a';
 
 
     /**
      * 'Z'.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte Z = (byte) 'Z';
 
 
     /**
      * '?'.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte QUESTION = (byte) '?';
 
 
     /**
      * Lower case offset.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final byte LC_OFFSET = A - a;
 
 
     /**
      * Default HTTP header buffer size.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 48 * 1024;
 
 
     /* Various constant "strings" */
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] CRLF_BYTES = ByteChunk.convertToBytes(CRLF);
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] COLON_BYTES = ByteChunk.convertToBytes(": ");
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final String CONNECTION = "Connection";
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final String CLOSE = "close";
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] CLOSE_BYTES =
         ByteChunk.convertToBytes(CLOSE);
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final String KEEPALIVE = "keep-alive";
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] KEEPALIVE_BYTES =
         ByteChunk.convertToBytes(KEEPALIVE);
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final String CHUNKED = "chunked";
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] ACK_BYTES =
         ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF);
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final String TRANSFERENCODING = "Transfer-Encoding";
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] _200_BYTES =
         ByteChunk.convertToBytes("200");
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] _400_BYTES =
         ByteChunk.convertToBytes("400");
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] _404_BYTES =
         ByteChunk.convertToBytes("404");
 
 
     /**
      * Identity filters (input and output).
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final int IDENTITY_FILTER = 0;
 
 
     /**
      * Chunked filters (input and output).
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final int CHUNKED_FILTER = 1;
 
 
     /**
      * Void filters (input and output).
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final int VOID_FILTER = 2;
 
 
     /**
      * GZIP filter (output).
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final int GZIP_FILTER = 3;
 
 
     /**
      * Buffered filter (input)
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final int BUFFERED_FILTER = 3;
 
 
     /**
      * HTTP/1.0.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final String HTTP_10 = "HTTP/1.0";
 
 
     /**
      * HTTP/1.1.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final String HTTP_11 = "HTTP/1.1";
+    /**
+     * @deprecated  Unused - will be removed in 8.0.x
+     */
+    @Deprecated
     public static final byte[] HTTP_11_BYTES =
         ByteChunk.convertToBytes(HTTP_11);
 
 
     /**
      * GET.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final String GET = "GET";
 
 
     /**
      * HEAD.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final String HEAD = "HEAD";
 
 
     /**
      * POST.
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final String POST = "POST";
 
 
diff --git a/java/org/apache/coyote/ajp/LocalStrings.properties b/java/org/apache/coyote/ajp/LocalStrings.properties
index 20773af..6451b6e 100644
--- a/java/org/apache/coyote/ajp/LocalStrings.properties
+++ b/java/org/apache/coyote/ajp/LocalStrings.properties
@@ -12,25 +12,13 @@
 # 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.
-
-# $Id: LocalStrings.properties 1301262 2012-03-15 23:05:15Z markt $
-
-# language 
-
-# package org.apache.coyote.ajp
-
-#
-# AjpAprProtocol
-#
-
 ajpprotocol.endpoint.starterror=Error starting endpoint
 ajpprotocol.init=Initializing Coyote AJP/1.3 on {0}
-ajpprotocol.proto.error=Error reading request, ignored
 ajpprotocol.start=Starting Coyote AJP/1.3 on {0}
-ajpprotocol.failedread=Socket read failed
 ajpprotocol.failedwrite=Socket write failed
 ajpprotocol.request.register=Error registering request processor in JMX
 
+ajpprocessor.failedread=Socket read failed
 ajpprocessor.failedflush=Failed to flush AJP message
 ajpprocessor.failedsend=Failed to send AJP message
 ajpprocessor.header.error=Header message parsing failed
diff --git a/java/org/apache/coyote/ajp/LocalStrings_es.properties b/java/org/apache/coyote/ajp/LocalStrings_es.properties
index 03d63c4..cec1733 100644
--- a/java/org/apache/coyote/ajp/LocalStrings_es.properties
+++ b/java/org/apache/coyote/ajp/LocalStrings_es.properties
@@ -16,9 +16,10 @@ ajpprotocol.endpoint.starterror = Error arrancando punto final
 ajpprotocol.init = Inicializando Coyote AJP/1.3 en {0}
 ajpprotocol.proto.error = Error leyendo requerimiento, ignorado
 ajpprotocol.start = Arrancando Coyote AJP/1.3 en {0}
-ajpprotocol.failedread = Fallo en lectura de Conector
 ajpprotocol.failedwrite = Fallo en escritura de Conector
 ajpprotocol.request.register = Error registrando procesador de requerimiento en JMX
+
+ajpprocessor.failedread = Fallo en lectura de Conector
 ajpprocessor.failedflush = No pude vaciar mensaje AJP
 ajpprocessor.failedsend = No pude enviar mensaje AJP
 ajpprocessor.header.error = Fallo en an\u00E1lisis de mensaje de cabecera
diff --git a/java/org/apache/coyote/http11/AbstractHttp11Processor.java b/java/org/apache/coyote/http11/AbstractHttp11Processor.java
index 1553ed7..c493ccc 100644
--- a/java/org/apache/coyote/http11/AbstractHttp11Processor.java
+++ b/java/org/apache/coyote/http11/AbstractHttp11Processor.java
@@ -767,6 +767,7 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                 // Set error flag
                 error = true;
             }
+
         } else if (actionCode == ActionCode.ACK) {
             // Acknowledge request
             // Send a 100 status back if it makes sense (response not committed
@@ -838,6 +839,8 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
             ((AtomicBoolean) param).set(asyncStateMachine.isAsync());
         } else if (actionCode == ActionCode.ASYNC_IS_TIMINGOUT) {
             ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut());
+        } else if (actionCode == ActionCode.ASYNC_IS_ERROR) {
+            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncError());
         } else if (actionCode == ActionCode.UPGRADE) {
             upgradeInbound = (UpgradeInbound) param;
             // Stop further HTTP output
@@ -1012,6 +1015,15 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                     setCometTimeouts(socketWrapper);
                 } catch (InterruptedIOException e) {
                     error = true;
+                } catch (HeadersTooLargeException e) {
+                    error = true;
+                    // The response should not have been committed but check it
+                    // anyway to be safe
+                    if (!response.isCommitted()) {
+                        response.reset();
+                        response.setStatus(500);
+                        response.setHeader("Connection", "close");
+                    }
                 } catch (Throwable t) {
                     ExceptionUtils.handleThrowable(t);
                     getLog().error(sm.getString(
@@ -1323,8 +1335,8 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
         }
 
         int statusCode = response.getStatus();
-        if ((statusCode == 204) || (statusCode == 205)
-            || (statusCode == 304)) {
+        if (statusCode < 200 || statusCode == 204 || statusCode == 205 ||
+                statusCode == 304) {
             // No entity body
             getOutputBuffer().addActiveFilter
                 (outputFilters[Constants.VOID_FILTER]);
@@ -1681,6 +1693,7 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
         localName = null;
         remotePort = -1;
         localPort = -1;
+        comet = false;
         recycleInternal();
     }
 
diff --git a/java/org/apache/coyote/http11/AbstractOutputBuffer.java b/java/org/apache/coyote/http11/AbstractOutputBuffer.java
index 1c70ae4..20ed768 100644
--- a/java/org/apache/coyote/http11/AbstractOutputBuffer.java
+++ b/java/org/apache/coyote/http11/AbstractOutputBuffer.java
@@ -250,7 +250,10 @@ public abstract class AbstractOutputBuffer<S> implements OutputBuffer{
 
         // Recycle Request object
         response.recycle();
-
+        // These will need to be reset if the reset was triggered by the error
+        // handling if the headers were too large
+        pos = 0;
+        byteCount = 0;
     }
     
     /**
@@ -538,10 +541,9 @@ public abstract class AbstractOutputBuffer<S> implements OutputBuffer{
      * Checks to see if there is enough space in the buffer to write the
      * requested number of bytes.
      */
-    private void checkLengthBeforeWrite(int length)
-            throws IllegalStateException {
+    private void checkLengthBeforeWrite(int length) {
         if (pos + length > buf.length) {
-            throw new IllegalStateException(
+            throw new HeadersTooLargeException(
                     sm.getString("iob.responseheadertoolarge.error"));
         }
     }
diff --git a/java/org/apache/coyote/http11/Constants.java b/java/org/apache/coyote/http11/Constants.java
index 20edc93..dbf531c 100644
--- a/java/org/apache/coyote/http11/Constants.java
+++ b/java/org/apache/coyote/http11/Constants.java
@@ -203,7 +203,10 @@ public final class Constants {
 
     /**
      * Has security been turned on?
+     *
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public static final boolean IS_SECURITY_ENABLED =
         (System.getSecurityManager() != null);
 }
diff --git a/java/org/apache/coyote/http11/HeadersTooLargeException.java b/java/org/apache/coyote/http11/HeadersTooLargeException.java
new file mode 100644
index 0000000..96d5133
--- /dev/null
+++ b/java/org/apache/coyote/http11/HeadersTooLargeException.java
@@ -0,0 +1,42 @@
+/*
+ *  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.coyote.http11;
+
+/**
+ * Exception used to mark the specific error condition of the HTTP headers
+ * exceeding the maximum permitted size.
+ */
+public class HeadersTooLargeException extends IllegalStateException {
+
+    private static final long serialVersionUID = 1L;
+
+    public HeadersTooLargeException() {
+        super();
+    }
+
+    public HeadersTooLargeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public HeadersTooLargeException(String s) {
+        super(s);
+    }
+
+    public HeadersTooLargeException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/org/apache/coyote/http11/Http11AprProtocol.java b/java/org/apache/coyote/http11/Http11AprProtocol.java
index 121e6c1..103d853 100644
--- a/java/org/apache/coyote/http11/Http11AprProtocol.java
+++ b/java/org/apache/coyote/http11/Http11AprProtocol.java
@@ -27,6 +27,7 @@ import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.net.AbstractEndpoint;
 import org.apache.tomcat.util.net.AprEndpoint;
 import org.apache.tomcat.util.net.AprEndpoint.Handler;
+import org.apache.tomcat.util.net.SocketStatus;
 import org.apache.tomcat.util.net.SocketWrapper;
 
 
@@ -53,6 +54,14 @@ public class Http11AprProtocol extends AbstractHttp11Protocol {
     }
 
 
+    @Override
+    public boolean isAprRequired() {
+        // Override since this protocol implementation requires the APR/native
+        // library
+        return true;
+    }
+
+
     public Http11AprProtocol() {
         endpoint = new AprEndpoint();
         cHandler = new Http11ConnectionHandler(this);
@@ -110,6 +119,17 @@ public class Http11AprProtocol extends AbstractHttp11Protocol {
 
 
     /**
+     * SSL honor cipher order.
+     *
+     * Set to <code>true</code> to enforce the <i>server's</i> cipher order
+     * instead of the default which is to allow the client to choose a
+     * preferred cipher.
+     */
+    public boolean getSSLHonorCipherOrder() { return ((AprEndpoint)endpoint).getSSLHonorCipherOrder(); }
+    public void setSSLHonorCipherOrder(boolean SSLHonorCipherOrder) { ((AprEndpoint)endpoint).setSSLHonorCipherOrder(SSLHonorCipherOrder); }
+
+
+    /**
      * SSL certificate file.
      */
     public String getSSLCertificateFile() { return ((AprEndpoint)endpoint).getSSLCertificateFile(); }
@@ -223,7 +243,8 @@ public class Http11AprProtocol extends AbstractHttp11Protocol {
             if (addToPoller && proto.endpoint.isRunning()) {
                 ((AprEndpoint)proto.endpoint).getPoller().add(
                         socket.getSocket().longValue(),
-                        proto.endpoint.getKeepAliveTimeout());
+                        proto.endpoint.getKeepAliveTimeout(),
+                        AprEndpoint.Poller.FLAGS_READ);
             }
         }
 
@@ -241,16 +262,25 @@ public class Http11AprProtocol extends AbstractHttp11Protocol {
             if (processor.isAsync()) {
                 // Async
                 socket.setAsync(true);
-            } else if (processor.isComet() && proto.endpoint.isRunning()) {
+            } else if (processor.isComet()) {
                 // Comet
-                ((AprEndpoint) proto.endpoint).getCometPoller().add(
-                        socket.getSocket().longValue(),
-                        proto.endpoint.getSoTimeout());
+                if (proto.endpoint.isRunning()) {
+                    ((AprEndpoint) proto.endpoint).getCometPoller().add(
+                            socket.getSocket().longValue(),
+                            proto.endpoint.getSoTimeout(),
+                            AprEndpoint.Poller.FLAGS_READ);
+                } else {
+                    // Process a STOP directly
+                    ((AprEndpoint) proto.endpoint).processSocket(
+                            socket.getSocket().longValue(),
+                            SocketStatus.STOP);
+                }
             } else {
                 // Upgraded
                 ((AprEndpoint) proto.endpoint).getPoller().add(
                         socket.getSocket().longValue(),
-                        (processor.getUpgradeInbound().getReadTimeout()));
+                        processor.getUpgradeInbound().getReadTimeout(),
+                        AprEndpoint.Poller.FLAGS_READ);
             }
         }
 
diff --git a/java/org/apache/coyote/http11/Http11NioProcessor.java b/java/org/apache/coyote/http11/Http11NioProcessor.java
index 2f83180..8828815 100644
--- a/java/org/apache/coyote/http11/Http11NioProcessor.java
+++ b/java/org/apache/coyote/http11/Http11NioProcessor.java
@@ -294,7 +294,6 @@ public class Http11NioProcessor extends AbstractHttp11Processor<NioChannel> {
     @Override
     public void recycleInternal() {
         socket = null;
-        comet = false;
         sendfileData = null;
     }
 
diff --git a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
index 00de536..088172d 100644
--- a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
+++ b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
@@ -144,7 +144,7 @@ public class ChunkedInputFilter implements InputFilter {
 
         if(needCRLFParse) {
             needCRLFParse = false;
-            parseCRLF();
+            parseCRLF(false);
         }
 
         if (remaining <= 0) {
@@ -179,7 +179,7 @@ public class ChunkedInputFilter implements InputFilter {
                 //so we defer it to the next call BZ 11117
                 needCRLFParse = true;
             } else {
-                parseCRLF(); //parse the CRLF immediately
+                parseCRLF(false); //parse the CRLF immediately
             }
         }
 
@@ -281,12 +281,14 @@ public class ChunkedInputFilter implements InputFilter {
 
     /**
      * Parse the header of a chunk.
-     * A chunk header can look like 
-     * A10CRLF
+     * A chunk header can look like one of the following:<br />
+     * A10CRLF<br />
      * F23;chunk-extension to be ignoredCRLF
-     * The letters before CRLF but after the trailer mark, must be valid hex digits, 
-     * we should not parse F23IAMGONNAMESSTHISUP34CRLF as a valid header
-     * according to spec
+     *
+     * <p>
+     * The letters before CRLF or ';' (whatever comes first) must be valid hex
+     * digits. We should not parse F23IAMGONNAMESSTHISUP34CRLF as a valid
+     * header according to the spec.
      */
     protected boolean parseChunkHeader()
         throws IOException {
@@ -303,18 +305,18 @@ public class ChunkedInputFilter implements InputFilter {
                     return false;
             }
 
-            if (buf[pos] == Constants.CR) {
-                // FIXME: Improve parsing to check for CRLF 
-            } else if (buf[pos] == Constants.LF) {
+            if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) {
+                parseCRLF(false);
                 eol = true;
             } else if (buf[pos] == Constants.SEMI_COLON) {
                 trailer = true;
             } else if (!trailer) { 
                 //don't read data after the trailer
-                if (HexUtils.getDec(buf[pos]) != -1) {
+                int charValue = HexUtils.getDec(buf[pos]);
+                if (charValue != -1) {
                     readDigit = true;
                     result *= 16;
-                    result += HexUtils.getDec(buf[pos]);
+                    result += charValue;
                 } else {
                     //we shouldn't allow invalid, non hex characters
                     //in the chunked header
@@ -322,7 +324,10 @@ public class ChunkedInputFilter implements InputFilter {
                 }
             }
 
-            pos++;
+            // Parsing the CRLF increments pos
+            if (!eol) {
+                pos++;
+            }
 
         }
 
@@ -343,9 +348,22 @@ public class ChunkedInputFilter implements InputFilter {
 
     /**
      * Parse CRLF at end of chunk.
+     * @deprecated  Use {@link #parseCRLF(boolean)}
      */
-    protected boolean parseCRLF()
-        throws IOException {
+    @Deprecated
+    protected boolean parseCRLF() throws IOException {
+        parseCRLF(false);
+        return true;
+    }
+
+    /**
+     * Parse CRLF at end of chunk.
+     *
+     * @param   tolerant    Should tolerant parsing (LF and CRLF) be used? This
+     *                      is recommended (RFC2616, section 19.3) for message
+     *                      headers.
+     */
+    protected void parseCRLF(boolean tolerant) throws IOException {
 
         boolean eol = false;
         boolean crfound = false;
@@ -361,7 +379,9 @@ public class ChunkedInputFilter implements InputFilter {
                 if (crfound) throw new IOException("Invalid CRLF, two CR characters encountered.");
                 crfound = true;
             } else if (buf[pos] == Constants.LF) {
-                if (!crfound) throw new IOException("Invalid CRLF, no CR character encountered.");
+                if (!tolerant && !crfound) {
+                    throw new IOException("Invalid CRLF, no CR character encountered.");
+                }
                 eol = true;
             } else {
                 throw new IOException("Invalid CRLF");
@@ -370,9 +390,6 @@ public class ChunkedInputFilter implements InputFilter {
             pos++;
 
         }
-
-        return true;
-
     }
 
 
@@ -393,26 +410,19 @@ public class ChunkedInputFilter implements InputFilter {
         MimeHeaders headers = request.getMimeHeaders();
 
         byte chr = 0;
-        while (true) {
-            // Read new bytes if needed
-            if (pos >= lastValid) {
-                if (readBytes() <0)
-                    throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
-            }
 
-            chr = buf[pos];
-    
-            if ((chr == Constants.CR) || (chr == Constants.LF)) {
-                if (chr == Constants.LF) {
-                    pos++;
-                    return false;
-                }
-            } else {
-                break;
-            }
+        // Read new bytes if needed
+        if (pos >= lastValid) {
+            if (readBytes() <0)
+                throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
+        }
     
-            pos++;
+        chr = buf[pos];
     
+        // CRLF terminates the request
+        if (chr == Constants.CR || chr == Constants.LF) {
+            parseCRLF(false);
+            return false;
         }
     
         // Mark the current buffer position
@@ -492,9 +502,8 @@ public class ChunkedInputFilter implements InputFilter {
                 }
     
                 chr = buf[pos];
-                if (chr == Constants.CR) {
-                    // Skip
-                } else if (chr == Constants.LF) {
+                if (chr == Constants.CR || chr == Constants.LF) {
+                    parseCRLF(true);
                     eol = true;
                 } else if (chr == Constants.SP) {
                     trailingHeaders.append(chr);
@@ -503,8 +512,9 @@ public class ChunkedInputFilter implements InputFilter {
                     lastSignificantChar = trailingHeaders.getEnd();
                 }
     
-                pos++;
-    
+                if (!eol) {
+                    pos++;
+                }
             }
     
             // Checking the first character of the new line. If the character
diff --git a/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java b/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java
index 4e683ed..e8feef6 100644
--- a/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java
+++ b/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java
@@ -42,6 +42,12 @@ public class FlushableGZIPOutputStream extends GZIPOutputStream {
     private byte[] lastByte = new byte[1];
     private boolean hasLastByte = false;
 
+    /**
+     * Flag that compression has to be re-enabled before the next write
+     * operation.
+     */
+    private boolean flagReenableCompression = false;
+
     @Override
     public void write(byte[] bytes) throws IOException {
         write(bytes, 0, bytes.length);
@@ -53,6 +59,7 @@ public class FlushableGZIPOutputStream extends GZIPOutputStream {
         if (length > 0) {
             flushLastByte();
             if (length > 1) {
+                reenableCompression();
                 super.write(bytes, offset, length - 1);
             }
             rememberLastByte(bytes[offset + length - 1]);
@@ -89,6 +96,13 @@ public class FlushableGZIPOutputStream extends GZIPOutputStream {
         super.close();
     }
 
+    private void reenableCompression() {
+        if (flagReenableCompression && !def.finished()) {
+            flagReenableCompression = false;
+            def.setLevel(Deflater.DEFAULT_COMPRESSION);
+        }
+    }
+
     private void rememberLastByte(byte b) {
         lastByte[0] = b;
         hasLastByte = true;
@@ -96,6 +110,7 @@ public class FlushableGZIPOutputStream extends GZIPOutputStream {
 
     private void flushLastByte() throws IOException {
         if (hasLastByte) {
+            reenableCompression();
             // Clear the flag first, because write() may fail
             hasLastByte = false;
             super.write(lastByte, 0, 1);
@@ -118,7 +133,7 @@ public class FlushableGZIPOutputStream extends GZIPOutputStream {
             if (!def.finished()) {
                 def.setLevel(Deflater.NO_COMPRESSION);
                 flushLastByte();
-                def.setLevel(Deflater.DEFAULT_COMPRESSION);
+                flagReenableCompression = true;
             }
         }
         out.flush();
@@ -139,5 +154,4 @@ public class FlushableGZIPOutputStream extends GZIPOutputStream {
             }
         } while (len != 0);
     }
-
 }
diff --git a/java/org/apache/coyote/http11/filters/IdentityInputFilter.java b/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
index 666afa2..dfa0584 100644
--- a/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
+++ b/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
@@ -81,7 +81,10 @@ public class IdentityInputFilter implements InputFilter {
 
     /**
      * Get content length.
+     *
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public long getContentLength() {
         return contentLength;
     }
@@ -89,7 +92,10 @@ public class IdentityInputFilter implements InputFilter {
 
     /**
      * Get remaining bytes.
+     *
+     * @deprecated  Unused - will be removed in 8.0.x
      */
+    @Deprecated
     public long getRemaining() {
         return remaining;
     }
diff --git a/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java b/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java
index dfce0a8..035a879 100644
--- a/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java
+++ b/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java
@@ -18,6 +18,7 @@ package org.apache.coyote.http11.upgrade;
 
 import java.io.EOFException;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.channels.Selector;
 
 import org.apache.tomcat.util.net.NioChannel;
@@ -120,9 +121,52 @@ public class UpgradeNioProcessor extends UpgradeProcessor<NioChannel> {
     private int readSocket(boolean block, byte[] bytes, int offset, int len)
             throws IOException {
 
-        int nRead = 0;
-        nioChannel.getBufHandler().getReadBuffer().clear();
-        nioChannel.getBufHandler().getReadBuffer().limit(len);
+        ByteBuffer readBuffer = nioChannel.getBufHandler().getReadBuffer();
+        int remaining = readBuffer.remaining();
+
+        // Is there enough data in the read buffer to satisfy this request?
+        if (remaining >= len) {
+            readBuffer.get(bytes, offset, len);
+            return len;
+        }
+
+        // Copy what data there is in the read buffer to the byte array
+        int leftToWrite = len;
+        int newOffset = offset;
+        if (remaining > 0) {
+            readBuffer.get(bytes, offset, remaining);
+            leftToWrite -= remaining;
+            newOffset += remaining;
+        }
+
+        // Fill the read buffer as best we can
+        readBuffer.clear();
+        int nRead = fillReadBuffer(block);
+
+        // Full as much of the remaining byte array as possible with the data
+        // that was just read
+        if (nRead > 0) {
+            readBuffer.flip();
+            readBuffer.limit(nRead);
+            if (nRead > leftToWrite) {
+                readBuffer.get(bytes, newOffset, leftToWrite);
+                leftToWrite = 0;
+            } else {
+                readBuffer.get(bytes, newOffset, nRead);
+                leftToWrite -= nRead;
+            }
+        } else if (nRead == 0) {
+            readBuffer.flip();
+            readBuffer.limit(nRead);
+        } else if (nRead == -1) {
+            throw new EOFException(sm.getString("nio.eof.error"));
+        }
+
+        return len - leftToWrite;
+    }
+
+    private int fillReadBuffer(boolean block) throws IOException {
+        int nRead;
         if (block) {
             Selector selector = null;
             try {
@@ -148,20 +192,9 @@ public class UpgradeNioProcessor extends UpgradeProcessor<NioChannel> {
         } else {
             nRead = nioChannel.read(nioChannel.getBufHandler().getReadBuffer());
         }
-        if (nRead > 0) {
-            nioChannel.getBufHandler().getReadBuffer().flip();
-            nioChannel.getBufHandler().getReadBuffer().limit(nRead);
-            nioChannel.getBufHandler().getReadBuffer().get(bytes, offset, nRead);
-            return nRead;
-        } else if (nRead == -1) {
-            //return false;
-            throw new EOFException(sm.getString("nio.eof.error"));
-        } else {
-            return 0;
-        }
+        return nRead;
     }
 
-
     /*
      * Adapted from the NioOutputBuffer
      */
diff --git a/java/org/apache/el/MethodExpressionImpl.java b/java/org/apache/el/MethodExpressionImpl.java
index cd91c97..3ab82ea 100644
--- a/java/org/apache/el/MethodExpressionImpl.java
+++ b/java/org/apache/el/MethodExpressionImpl.java
@@ -72,7 +72,7 @@ import org.apache.el.util.ReflectionUtil;
  * @see javax.el.MethodExpression
  * 
  * @author Jacob Hookom [jacob at hookom.net]
- * @version $Id: MethodExpressionImpl.java 1026769 2010-10-24 11:55:10Z markt $
+ * @version $Id: MethodExpressionImpl.java 1379214 2012-08-30 23:13:32Z markt $
  */
 public final class MethodExpressionImpl extends MethodExpression implements
         Externalizable {
@@ -206,10 +206,6 @@ public final class MethodExpressionImpl extends MethodExpression implements
         return n.getMethodInfo(ctx, this.paramTypes);
     }
 
-    /**
-     * @return
-     * @throws ELException
-     */
     private Node getNode() throws ELException {
         if (this.node == null) {
             this.node = ExpressionBuilder.createNode(this.expr);
diff --git a/java/org/apache/el/ValueExpressionImpl.java b/java/org/apache/el/ValueExpressionImpl.java
index a8e79c9..fdd00f9 100644
--- a/java/org/apache/el/ValueExpressionImpl.java
+++ b/java/org/apache/el/ValueExpressionImpl.java
@@ -85,7 +85,7 @@ import org.apache.el.util.ReflectionUtil;
  * @see javax.el.ValueExpression
  * 
  * @author Jacob Hookom [jacob at hookom.net]
- * @version $Id: ValueExpressionImpl.java 1026769 2010-10-24 11:55:10Z markt $
+ * @version $Id: ValueExpressionImpl.java 1379214 2012-08-30 23:13:32Z markt $
  */
 public final class ValueExpressionImpl extends ValueExpression implements
         Externalizable {
@@ -152,10 +152,6 @@ public final class ValueExpressionImpl extends ValueExpression implements
         return this.expr;
     }
 
-    /**
-     * @return
-     * @throws ELException
-     */
     private Node getNode() throws ELException {
         if (this.node == null) {
             this.node = ExpressionBuilder.createNode(this.expr);
diff --git a/java/org/apache/el/parser/AstValue.java b/java/org/apache/el/parser/AstValue.java
index 8141baa..3baf1b0 100644
--- a/java/org/apache/el/parser/AstValue.java
+++ b/java/org/apache/el/parser/AstValue.java
@@ -38,7 +38,7 @@ import org.apache.el.util.ReflectionUtil;
 
 /**
  * @author Jacob Hookom [jacob at hookom.net]
- * @version $Id: AstValue.java 1304933 2012-03-24 21:33:47Z markt $
+ * @version $Id: AstValue.java 1379737 2012-09-01 10:25:51Z markt $
  */
 public final class AstValue extends SimpleNode {
 
@@ -103,39 +103,53 @@ public final class AstValue extends SimpleNode {
         Object property = null;
         int propCount = this.jjtGetNumChildren();
         
-        if (propCount > 2 &&
-                this.jjtGetChild(propCount - 1) instanceof AstMethodParameters) {
-            // Method call with paramaters. 
-            propCount-=2;
-        } else {
-            propCount--;
-        }
         int i = 1;
-
-        // evaluate any properties before our target
+        // Evaluate any properties or methods before our target
         ELResolver resolver = ctx.getELResolver();
-        if (propCount > 1) {
-            while (base != null && i < propCount) {
+        while (i < propCount) {
+            if (i + 2 < propCount &&
+                    this.children[i + 1] instanceof AstMethodParameters) {
+                // Method call not at end of expression
+                base = resolver.invoke(ctx, base,
+                        this.children[i].getValue(ctx), null,
+                        ((AstMethodParameters)
+                                this.children[i + 1]).getParameters(ctx));
+                i += 2;
+            } else if (i + 2 == propCount &&
+                    this.children[i + 1] instanceof AstMethodParameters) {
+                // Method call at end of expression
+                ctx.setPropertyResolved(false);
+                property = this.children[i].getValue(ctx);
+                i += 2;
+
+                if (property == null) {
+                    throw new PropertyNotFoundException(MessageFactory.get(
+                            "error.unreachable.property", property));
+                }
+            } else if (i + 1 < propCount) {
+                // Object with property not at end of expression
                 property = this.children[i].getValue(ctx);
                 ctx.setPropertyResolved(false);
                 base = resolver.getValue(ctx, base, property);
                 i++;
+
+            } else {
+                // Object with property at end of expression
+                ctx.setPropertyResolved(false);
+                property = this.children[i].getValue(ctx);
+                i++;
+
+                if (property == null) {
+                    throw new PropertyNotFoundException(MessageFactory.get(
+                            "error.unreachable.property", property));
+                }
             }
-            // if we are in this block, we have more properties to resolve,
-            // but our base was null
-            if (base == null || property == null) {
+            if (base == null) {
                 throw new PropertyNotFoundException(MessageFactory.get(
                         "error.unreachable.property", property));
             }
         }
 
-        property = this.children[i].getValue(ctx);
-
-        if (property == null) {
-            throw new PropertyNotFoundException(MessageFactory.get(
-                    "error.unreachable.property", this.children[i]));
-        }
-
         Target t = new Target();
         t.base = base;
         t.property = property;
diff --git a/java/org/apache/jasper/Constants.java b/java/org/apache/jasper/Constants.java
index 60ff5e3..632ab87 100644
--- a/java/org/apache/jasper/Constants.java
+++ b/java/org/apache/jasper/Constants.java
@@ -219,4 +219,18 @@ public class Constants {
      * the tomcat instance installation path
      */
     public static final String CATALINA_BASE_PROP = "catalina.base";
+
+    /**
+     * Name of system property containing default list of JARs to skip when
+     * scanning JARs for configuration elements such as TLDs.
+     */
+    public static final String DEFAULT_JAR_SKIP_PROP=
+            "tomcat.util.scan.DefaultJarScanner.jarsToSkip";
+
+    /**
+     * Name of system property containing additional list of JARs to skip when
+     * scanning for TLDs.
+     */
+    public static final String TLD_JAR_SKIP_PROP=
+            "org.apache.catalina.startup.TldConfig.jarsToSkip";
 }
diff --git a/java/org/apache/jasper/compiler/Compiler.java b/java/org/apache/jasper/compiler/Compiler.java
index 3772862..d737b9c 100644
--- a/java/org/apache/jasper/compiler/Compiler.java
+++ b/java/org/apache/jasper/compiler/Compiler.java
@@ -108,7 +108,7 @@ public abstract class Compiler {
 
         // Setup page info area
         pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(),
-                errDispatcher), ctxt.getJspFile());
+                errDispatcher), ctxt.getJspFile(), ctxt.isTagFile());
 
         JspConfig jspConfig = options.getJspConfig();
         JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(ctxt
@@ -496,7 +496,7 @@ public abstract class Compiler {
             try {
                 String key = include.getKey();
                 URL includeUrl;
-                if (key.startsWith("jar:")) {
+                if (key.startsWith("jar:") || key.startsWith("file:")) {
                     includeUrl = new URL(key);
                 } else {
                     includeUrl = ctxt.getResource(include.getKey());
diff --git a/java/org/apache/jasper/compiler/Generator.java b/java/org/apache/jasper/compiler/Generator.java
index 0c8a227..08fdf8f 100644
--- a/java/org/apache/jasper/compiler/Generator.java
+++ b/java/org/apache/jasper/compiler/Generator.java
@@ -3176,7 +3176,7 @@ class Generator {
             } else if (c == Long.class) {
                 return JspUtil.coerceToLong(s, isNamedAttribute);
             } else if (c == Object.class) {
-                return "new String(" + quoted + ")";
+                return quoted;
             } else {
                 String className = c.getCanonicalName();
                 return "("
@@ -3395,7 +3395,7 @@ class Generator {
         out.printil("try { out.clearBuffer(); } catch (java.io.IOException e) {}");
         out.popIndent();
         out.printil("if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);");
-        out.printil("else log(t.getMessage(), t);");
+        out.printil("else throw new ServletException(t);");
         out.popIndent();
         out.printil("}");
         out.popIndent();
diff --git a/java/org/apache/jasper/compiler/JspReader.java b/java/org/apache/jasper/compiler/JspReader.java
index 09ae740..526e2ae 100644
--- a/java/org/apache/jasper/compiler/JspReader.java
+++ b/java/org/apache/jasper/compiler/JspReader.java
@@ -193,6 +193,65 @@ class JspReader {
     }
 
     /**
+     * A faster approach than calling {@link #mark()} & {@link #nextChar()}.
+     * However, this approach is only safe if the mark is only used within the
+     * JspReader.
+     */
+    private int nextChar(Mark mark) throws JasperException {
+        if (!hasMoreInput()) {
+            return -1;
+        }
+
+        int ch = current.stream[current.cursor];
+
+        mark.init(current, singleFile);
+
+        current.cursor++;
+
+        if (ch == '\n') {
+            current.line++;
+            current.col = 0;
+        } else {
+            current.col++;
+        }
+        return ch;
+    }
+
+    /**
+     * Search the given character, If it was found, then mark the current cursor
+     * and the cursor point to next character.
+     */
+    private Boolean indexOf(char c, Mark mark) throws JasperException {
+        if (!hasMoreInput())
+            return null;
+
+        int end = current.stream.length;
+        int ch;
+        int line = current.line;
+        int col = current.col;
+        int i = current.cursor;
+        for(; i < end; i ++) {
+           ch = current.stream[i];
+
+           if (ch == c) {
+               mark.update(i, line, col);
+           }
+           if (ch == '\n') {
+                line++;
+                col = 0;
+            } else {
+                col++;
+            }
+           if (ch == c) {
+               current.update(i+1, line, col);
+               return Boolean.TRUE;
+           }
+        }
+        current.update(i, line, col);
+        return Boolean.FALSE;
+    }
+
+    /**
      * Back up the current cursor by one char, assumes current.cursor > 0,
      * and that the char to be pushed back is not '\n'.
      */
@@ -205,10 +264,11 @@ class JspReader {
         Mark oldstart = mark();
         reset(start);
         CharArrayWriter caw = new CharArrayWriter();
-        while (!stop.equals(mark()))
+        while (!markEquals(stop)) {
             caw.write(nextChar());
+        }
         caw.close();
-        reset(oldstart);
+        setCurrent(oldstart);
         return caw.toString();
     }
 
@@ -222,11 +282,27 @@ class JspReader {
         return new Mark(current);
     }
 
+
+    /**
+     * This method avoids a call to {@link #mark()} when doing comparison.
+     */
+    private boolean markEquals(Mark another) {
+       return another.equals(current);
+    }
+
     void reset(Mark mark) {
         current = new Mark(mark);
     }
 
     /**
+     * Similar to {@link #reset(Mark)} but no new Mark will be created.
+     * Therefore, the parameter mark must NOT be used in other places.
+     */
+    private void setCurrent(Mark mark) {
+       current = mark;
+    }
+
+    /**
      * search the stream for a match to a string
      * @param string The string to match
      * @return <strong>true</strong> is one is found, the current position
@@ -234,17 +310,40 @@ class JspReader {
      *               false</strong> otherwise, position in stream unchanged.
      */
     boolean matches(String string) throws JasperException {
-        Mark mark = mark();
-        int ch = 0;
-        int i = 0;
-        do {
-            ch = nextChar();
-            if (((char) ch) != string.charAt(i++)) {
-                reset(mark);
-                return false;
-            }
-        } while (i < string.length());
-        return true;
+       int len = string.length();
+       int cursor = current.cursor;
+       int streamSize = current.stream.length;
+       if (cursor + len < streamSize) { //Try to scan in memory
+           int line = current.line;
+           int col = current.col;
+           int ch;
+           int i = 0;
+           for(; i < len; i ++) {
+               ch = current.stream[i+cursor];
+               if (string.charAt(i) != ch) {
+                   return false;
+               }
+               if (ch == '\n') {
+                  line ++;
+                  col = 0;
+               } else {
+                  col++;
+               }
+           }
+           current.update(i+cursor, line, col);
+       } else {
+           Mark mark = mark();
+           int ch = 0;
+           int i = 0;
+           do {
+               ch = nextChar();
+               if (((char) ch) != string.charAt(i++)) {
+                   setCurrent(mark);
+                   return false;
+               }
+           } while (i < len);
+       }
+       return true;
     }
 
     boolean matchesETag(String tagName) throws JasperException {
@@ -256,7 +355,7 @@ class JspReader {
         if (nextChar() == '>')
             return true;
 
-        reset(mark);
+        setCurrent(mark);
         return false;
     }
 
@@ -271,7 +370,7 @@ class JspReader {
        if (nextChar() == '>')
            return true;
 
-       reset(mark);
+       setCurrent(mark);
        return false;
     }
 
@@ -290,7 +389,7 @@ class JspReader {
         skipSpaces();
         boolean result = matches( s );
         if( !result ) {
-            reset( mark );
+            setCurrent(mark);
         }
 
         return result;
@@ -315,24 +414,29 @@ class JspReader {
      *         otherwise.
      */
     Mark skipUntil(String limit) throws JasperException {
-        Mark ret = null;
+        Mark ret = mark();
         int limlen = limit.length();
-        int ch;
+        char firstChar = limit.charAt(0);
+        Boolean result = null;
+        Mark restart = null;
 
     skip:
-        for (ret = mark(), ch = nextChar() ; ch != -1 ;
-                 ret = mark(), ch = nextChar()) {
-            if (ch == limit.charAt(0)) {
-                Mark restart = mark();
-                for (int i = 1 ; i < limlen ; i++) {
-                    if (peekChar() == limit.charAt(i))
-                        nextChar();
-                    else {
-                        reset(restart);
-                        continue skip;
-                    }
-                }
-                return ret;
+        while((result = indexOf(firstChar, ret)) != null) {
+           if (result.booleanValue()) {
+               if (restart != null) {
+                   restart.init(current, singleFile);
+               } else {
+                   restart = mark();
+               }
+               for (int i = 1 ; i < limlen ; i++) {
+                   if (peekChar() == limit.charAt(i)) {
+                       nextChar();
+                   } else {
+                       current.init(restart, singleFile);
+                       continue skip;
+                   }
+               }
+               return ret;
             }
         }
         return null;
@@ -349,18 +453,16 @@ class JspReader {
      *         otherwise.
      */
     Mark skipUntilIgnoreEsc(String limit) throws JasperException {
-        Mark ret = null;
+        Mark ret = mark();
         int limlen = limit.length();
         int ch;
         int prev = 'x';        // Doesn't matter
-        
+        char firstChar = limit.charAt(0);
     skip:
-        for (ret = mark(), ch = nextChar() ; ch != -1 ;
-                 ret = mark(), prev = ch, ch = nextChar()) {            
+        for (ch = nextChar(ret) ; ch != -1 ; prev = ch, ch = nextChar(ret)) {
             if (ch == '\\' && prev == '\\') {
                 ch = 0;                // Double \ is not an escape char anymore
-            }
-            else if (ch == limit.charAt(0) && prev != '\\') {
+            } else if (ch == firstChar && prev != '\\') {
                 for (int i = 1 ; i < limlen ; i++) {
                     if (peekChar() == limit.charAt(i))
                         nextChar();
@@ -477,10 +579,10 @@ class JspReader {
                 Mark mark = mark();
                 if (((ch = nextChar()) == '>')
                         || ((ch == '-') && (nextChar() == '>'))) {
-                    reset(mark);
+                    setCurrent(mark);
                     return true;
                 } else {
-                    reset(mark);
+                    setCurrent(mark);
                     return false;
                 }
             }
diff --git a/java/org/apache/jasper/compiler/Mark.java b/java/org/apache/jasper/compiler/Mark.java
index 5cf6653..e335ed5 100644
--- a/java/org/apache/jasper/compiler/Mark.java
+++ b/java/org/apache/jasper/compiler/Mark.java
@@ -89,22 +89,37 @@ final class Mark {
      * Constructor
      */
     Mark(Mark other) {
+       init(other, false);
+    }
+
+    void update(int cursor, int line, int col) {
+        this.cursor = cursor;
+        this.line = line;
+        this.col = col;
+    }
 
-        this.reader = other.reader;
-        this.ctxt = other.reader.getJspCompilationContext();
-        this.stream = other.stream;
-        this.fileId = other.fileId;
-        this.fileName = other.fileName;
+    void init(Mark other, boolean singleFile) {
         this.cursor = other.cursor;
         this.line = other.line;
         this.col = other.col;
-        this.baseDir = other.baseDir;
-        this.encoding = other.encoding;
 
-        // clone includeStack without cloning contents
-        includeStack = new Stack<IncludeState>();
-        for ( int i=0; i < other.includeStack.size(); i++ ) {
-            includeStack.addElement( other.includeStack.elementAt(i) );
+        if (!singleFile) {
+            this.reader = other.reader;
+            this.ctxt = other.ctxt;
+            this.stream = other.stream;
+            this.fileId = other.fileId;
+            this.fileName = other.fileName;
+            this.baseDir = other.baseDir;
+            this.encoding = other.encoding;
+
+            if (includeStack == null) {
+                includeStack = new Stack<IncludeState>();
+            } else {
+                includeStack.clear();
+            }
+            for (int i = 0; i < other.includeStack.size(); i++ ) {
+                includeStack.addElement(other.includeStack.elementAt(i));
+            }
         }
     }
 
diff --git a/java/org/apache/jasper/compiler/PageInfo.java b/java/org/apache/jasper/compiler/PageInfo.java
index 72508e5..d22a5c8 100644
--- a/java/org/apache/jasper/compiler/PageInfo.java
+++ b/java/org/apache/jasper/compiler/PageInfo.java
@@ -99,8 +99,10 @@ class PageInfo {
     // JSP 2.2
     private boolean errorOnUndeclaredNamepsace = false;
 
-    PageInfo(BeanRepository beanRepository, String jspFile) {
+    private boolean isTagFile = false;
 
+    PageInfo(BeanRepository beanRepository, String jspFile, boolean isTagFile) {
+        this.isTagFile = isTagFile;
         this.jspFile = jspFile;
         this.beanRepository = beanRepository;
         this.varInfoNames = new HashSet<String>();
@@ -119,6 +121,10 @@ class PageInfo {
         imports.addAll(Constants.STANDARD_IMPORTS);
     }
 
+    public boolean isTagFile() {
+        return isTagFile;
+    }
+
     /**
      * Check if the plugin ID has been previously declared.  Make a not
      * that this Id is now declared.
diff --git a/java/org/apache/jasper/compiler/TagPluginManager.java b/java/org/apache/jasper/compiler/TagPluginManager.java
index 63d324d..6664df2 100644
--- a/java/org/apache/jasper/compiler/TagPluginManager.java
+++ b/java/org/apache/jasper/compiler/TagPluginManager.java
@@ -243,6 +243,11 @@ public class TagPluginManager {
             curNodes = node.getAtETag();
         }
 
+        @Override
+        public boolean isTagFile() {
+            return pageInfo.isTagFile();
+        }
+
         private Node.JspAttribute getNodeAttribute(String attribute) {
             Node.JspAttribute[] attrs = node.getJspAttributes();
             for (int i=0; attrs != null && i < attrs.length; i++) {
diff --git a/java/org/apache/jasper/compiler/TldLocationsCache.java b/java/org/apache/jasper/compiler/TldLocationsCache.java
index b54c037..97f3cbf 100644
--- a/java/org/apache/jasper/compiler/TldLocationsCache.java
+++ b/java/org/apache/jasper/compiler/TldLocationsCache.java
@@ -30,6 +30,7 @@ import java.util.StringTokenizer;
 
 import javax.servlet.ServletContext;
 
+import org.apache.jasper.Constants;
 import org.apache.jasper.JasperException;
 import org.apache.jasper.util.ExceptionUtils;
 import org.apache.jasper.xmlparser.ParserUtils;
@@ -100,36 +101,33 @@ public class TldLocationsCache {
     // there are JARs that could be skipped
     private static volatile boolean showTldScanWarning = true;
 
-    /**
-     * The mapping of the 'global' tag library URI to the location (resource
-     * path) of the TLD associated with that tag library. The location is
-     * returned as a String array:
-     *    [0] The location
-     *    [1] If the location is a jar file, this is the location of the tld.
-     */
-    private Hashtable<String, TldLocation> mappings;
+    static {
+        // Set the default list of JARs to skip for TLDs
+        // Set the default list of JARs to skip for TLDs
+        StringBuilder jarList = new StringBuilder(System.getProperty(
+                Constants.DEFAULT_JAR_SKIP_PROP, ""));
 
-    private volatile boolean initialized;
-    private ServletContext ctxt;
+        String tldJars = System.getProperty(Constants.TLD_JAR_SKIP_PROP, "");
+        if (tldJars.length() > 0) {
+            if (jarList.length() > 0) {
+                jarList.append(',');
+            }
+            jarList.append(tldJars);
+        }
 
-    /** Constructor. 
-     *
-     * @param ctxt the servlet context of the web application in which Jasper 
-     * is running
-     */
-    public TldLocationsCache(ServletContext ctxt) {
-        this.ctxt = ctxt;
-        mappings = new Hashtable<String, TldLocation>();
-        initialized = false;
+        if (jarList.length() > 0) {
+            setNoTldJars(jarList.toString());
+        }
     }
 
+
     /**
      * Sets the list of JARs that are known not to contain any TLDs.
      *
      * @param jarNames List of comma-separated names of JAR files that are 
      * known not to contain any TLDs 
      */
-    public static void setNoTldJars(String jarNames) {
+    public static synchronized void setNoTldJars(String jarNames) {
         if (jarNames == null) {
             noTldJars = null;
         } else {
@@ -147,6 +145,29 @@ public class TldLocationsCache {
 
 
     /**
+     * The mapping of the 'global' tag library URI to the location (resource
+     * path) of the TLD associated with that tag library. The location is
+     * returned as a String array:
+     *    [0] The location
+     *    [1] If the location is a jar file, this is the location of the tld.
+     */
+    private Hashtable<String, TldLocation> mappings;
+
+    private volatile boolean initialized;
+    private ServletContext ctxt;
+
+    /** Constructor.
+     *
+     * @param ctxt the servlet context of the web application in which Jasper
+     * is running
+     */
+    public TldLocationsCache(ServletContext ctxt) {
+        this.ctxt = ctxt;
+        mappings = new Hashtable<String, TldLocation>();
+        initialized = false;
+    }
+
+    /**
      * Obtains the TLD location cache for the given {@link ServletContext} and
      * creates one if one does not currently exist.
      */
diff --git a/java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java b/java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java
index f9d1db5..7bd4683 100644
--- a/java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java
+++ b/java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java
@@ -120,5 +120,10 @@ public interface TagPluginContext {
      * Get the value of an attribute in the current tagplugin context.
      */
     Object getPluginAttribute(String attr);
+
+    /**
+     * Is the tag being used inside a tag file?
+     */
+    boolean isTagFile();
 }
 
diff --git a/java/org/apache/jasper/el/JasperELResolver.java b/java/org/apache/jasper/el/JasperELResolver.java
new file mode 100644
index 0000000..7349711
--- /dev/null
+++ b/java/org/apache/jasper/el/JasperELResolver.java
@@ -0,0 +1,163 @@
+/*
+ * 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.jasper.el;
+
+import java.util.List;
+
+import javax.el.ArrayELResolver;
+import javax.el.BeanELResolver;
+import javax.el.CompositeELResolver;
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.ListELResolver;
+import javax.el.MapELResolver;
+import javax.el.PropertyNotFoundException;
+import javax.el.ResourceBundleELResolver;
+import javax.servlet.jsp.el.ImplicitObjectELResolver;
+import javax.servlet.jsp.el.ScopedAttributeELResolver;
+
+/**
+ * Jasper-specific CompositeELResolver that optimizes certain functions to avoid
+ * unnecessary resolver calls.
+ */
+public class JasperELResolver extends CompositeELResolver {
+
+    private int size;
+    private ELResolver[] resolvers;
+    private final int appResolversSize;
+
+    public JasperELResolver(List<ELResolver> appResolvers) {
+        appResolversSize = appResolvers.size();
+        resolvers = new ELResolver[appResolversSize + 7];
+        size = 0;
+
+        add(new ImplicitObjectELResolver());
+        for (ELResolver appResolver : appResolvers) {
+            add(appResolver);
+        }
+        add(new MapELResolver());
+        add(new ResourceBundleELResolver());
+        add(new ListELResolver());
+        add(new ArrayELResolver());
+        add(new BeanELResolver());
+        add(new ScopedAttributeELResolver());
+    }
+
+    @Override
+    public synchronized void add(ELResolver elResolver) {
+        super.add(elResolver);
+
+        if (resolvers.length < size) {
+            resolvers[size] = elResolver;
+        } else {
+            ELResolver[] nr = new ELResolver[size + 1];
+            System.arraycopy(resolvers, 0, nr, 0, size);
+            nr[size] = elResolver;
+
+            resolvers = nr;
+        }
+        size ++;
+    }
+
+    @Override
+    public Object getValue(ELContext context, Object base, Object property)
+        throws NullPointerException, PropertyNotFoundException, ELException {
+        context.setPropertyResolved(false);
+
+        int start;
+        Object result = null;
+
+        if (base == null) {
+            // call implicit and app resolvers
+            int index = 1 /* implicit */ + appResolversSize;
+            for (int i = 0; i < index; i++) {
+                result = resolvers[i].getValue(context, base, property);
+                if (context.isPropertyResolved()) {
+                    return result;
+                }
+            }
+            // skip collection-based resolvers (map, resource, list, array, and
+            // bean)
+            start = index + 5;
+        } else {
+            // skip implicit resolver only
+            start = 1;
+        }
+
+        for (int i = start; i < size; i++) {
+            result = resolvers[i].getValue(context, base, property);
+            if (context.isPropertyResolved()) {
+                return result;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public Object invoke(ELContext context, Object base, Object method,
+            Class<?>[] paramTypes, Object[] params) {
+        String targetMethod = coerceToString(method);
+        if (targetMethod.length() == 0) {
+            throw new ELException(new NoSuchMethodException());
+        }
+
+        context.setPropertyResolved(false);
+
+        Object result = null;
+
+        // skip implicit and call app resolvers
+        int index = 1 /* implicit */ + appResolversSize;
+        for (int i = 1; i < index; i++) {
+            result = resolvers[i].invoke(
+                    context, base, targetMethod, paramTypes, params);
+            if (context.isPropertyResolved()) {
+                return result;
+            }
+        }
+
+        // skip map, resource, list, and array resolvers
+        index += 4;
+        // call bean and the rest of resolvers
+        for (int i = index; i < size; i++) {
+            result = resolvers[i].invoke(
+                    context, base, targetMethod, paramTypes, params);
+            if (context.isPropertyResolved()) {
+                return result;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Copied from {@link org.apache.el.lang.ELSupport#coerceToString(Object)}.
+     */
+    private static final String coerceToString(final Object obj) {
+        if (obj == null) {
+            return "";
+        } else if (obj instanceof String) {
+            return (String) obj;
+        } else if (obj instanceof Enum<?>) {
+            return ((Enum<?>) obj).name();
+        } else {
+            return obj.toString();
+        }
+    }
+}
\ No newline at end of file
diff --git a/java/org/apache/jasper/resources/LocalStrings.properties b/java/org/apache/jasper/resources/LocalStrings.properties
index 4b67a9c..b0a77d5 100644
--- a/java/org/apache/jasper/resources/LocalStrings.properties
+++ b/java/org/apache/jasper/resources/LocalStrings.properties
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# $Id: LocalStrings.properties 1136073 2011-06-15 14:48:11Z kkolinko $
+# $Id: LocalStrings.properties 1377085 2012-08-24 20:21:07Z markt $
 #
 # Default localized string information
 # Localized this the Default Locale as is en_US
@@ -490,5 +490,5 @@ jsp.message.jsp_unload_check=Checking JSPs for unload in context [{0}], JSP coun
 
 xmlParser.skipBomFail=Failed to skip BOM when parsing XML input stream
 
-jsp.tldCache.noTldInJar=No TLD files were found in [{0}]. Consider adding the JAR to the tomcat.util.scan.DefaultJarScanner.jarsToSkip property in CATALINA_BASE/conf/catalina.properties file.
+jsp.tldCache.noTldInJar=No TLD files were found in [{0}]. Consider adding the JAR to the tomcat.util.scan.DefaultJarScanner.jarsToSkip or org.apache.catalina.startup.TldConfig.jarsToSkip property in CATALINA_BASE/conf/catalina.properties file.
 jsp.tldCache.noTldSummary=At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
diff --git a/java/org/apache/jasper/runtime/JspApplicationContextImpl.java b/java/org/apache/jasper/runtime/JspApplicationContextImpl.java
index 723263f..126f180 100644
--- a/java/org/apache/jasper/runtime/JspApplicationContextImpl.java
+++ b/java/org/apache/jasper/runtime/JspApplicationContextImpl.java
@@ -5,9 +5,9 @@
  * 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.
@@ -19,31 +19,24 @@ package org.apache.jasper.runtime;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
-import javax.el.ArrayELResolver;
-import javax.el.BeanELResolver;
 import javax.el.CompositeELResolver;
 import javax.el.ELContextEvent;
 import javax.el.ELContextListener;
 import javax.el.ELResolver;
 import javax.el.ExpressionFactory;
-import javax.el.ListELResolver;
-import javax.el.MapELResolver;
-import javax.el.ResourceBundleELResolver;
 import javax.servlet.ServletContext;
 import javax.servlet.jsp.JspApplicationContext;
 import javax.servlet.jsp.JspContext;
-import javax.servlet.jsp.el.ImplicitObjectELResolver;
-import javax.servlet.jsp.el.ScopedAttributeELResolver;
 
 import org.apache.jasper.Constants;
 import org.apache.jasper.el.ELContextImpl;
+import org.apache.jasper.el.JasperELResolver;
 
 /**
  * Implementation of JspApplicationContext
- * 
+ *
  * @author Jacob Hookom
  */
 public class JspApplicationContextImpl implements JspApplicationContext {
@@ -119,18 +112,7 @@ public class JspApplicationContextImpl implements JspApplicationContext {
     private ELResolver createELResolver() {
         this.instantiated = true;
         if (this.resolver == null) {
-            CompositeELResolver r = new CompositeELResolver();
-            r.add(new ImplicitObjectELResolver());
-            for (Iterator<ELResolver> itr = this.resolvers.iterator();
-                    itr.hasNext();) {
-                r.add(itr.next());
-            }
-            r.add(new MapELResolver());
-            r.add(new ResourceBundleELResolver());
-            r.add(new ListELResolver());
-            r.add(new ArrayELResolver());    
-            r.add(new BeanELResolver());
-            r.add(new ScopedAttributeELResolver());
+            CompositeELResolver r = new JasperELResolver(this.resolvers);
             this.resolver = r;
         }
         return this.resolver;
diff --git a/java/org/apache/jasper/runtime/JspFactoryImpl.java b/java/org/apache/jasper/runtime/JspFactoryImpl.java
index 74a1431..da32f61 100644
--- a/java/org/apache/jasper/runtime/JspFactoryImpl.java
+++ b/java/org/apache/jasper/runtime/JspFactoryImpl.java
@@ -114,6 +114,9 @@ public class JspFactoryImpl extends JspFactory {
             return pc;
         } catch (Throwable ex) {
             ExceptionUtils.handleThrowable(ex);
+            if (ex instanceof RuntimeException) {
+                throw (RuntimeException) ex;
+            }
             log.fatal("Exception initializing page context", ex);
             return null;
         }
diff --git a/java/org/apache/jasper/runtime/PageContextImpl.java b/java/org/apache/jasper/runtime/PageContextImpl.java
index 94a1ba4..a3156ac 100644
--- a/java/org/apache/jasper/runtime/PageContextImpl.java
+++ b/java/org/apache/jasper/runtime/PageContextImpl.java
@@ -723,6 +723,7 @@ public class PageContextImpl extends PageContext {
         // JSP.4.5 If the buffer was flushed, throw IllegalStateException
         try {
             out.clear();
+            baseOut.clear();
         } catch (IOException ex) {
             IllegalStateException ise = new IllegalStateException(Localizer
                     .getMessage("jsp.error.attempt_to_clear_flushed_buffer"));
@@ -912,27 +913,67 @@ public class PageContextImpl extends PageContext {
         }
     }
 
-    private static String XmlEscape(String s) {
-        if (s == null)
+    protected static String XmlEscape(String s) {
+        if (s == null) {
             return null;
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < s.length(); i++) {
+        }
+        int len = s.length();
+
+        /*
+         * Look for any "bad" characters, Escape "bad" character was found
+         */
+        // ASCII " 34 & 38 ' 39 < 60 > 62
+        for (int i = 0; i < len; i++) {
             char c = s.charAt(i);
-            if (c == '<') {
-                sb.append("<");
-            } else if (c == '>') {
-                sb.append(">");
-            } else if (c == '\'') {
-                sb.append("'"); // '
-            } else if (c == '&') {
-                sb.append("&");
-            } else if (c == '"') {
-                sb.append("""); // "
-            } else {
-                sb.append(c);
+            if (c >= '\"' && c <= '>' &&
+                    (c == '<' || c == '>' || c == '\'' || c == '&' || c == '"')) {
+                // need to escape them and then quote the whole string
+                StringBuilder sb = new StringBuilder((int) (len * 1.2));
+                sb.append(s, 0, i);
+                int pos = i + 1;
+                for (int j = i; j < len; j++) {
+                    c = s.charAt(j);
+                    if (c >= '\"' && c <= '>') {
+                        if (c == '<') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append("<");
+                            pos = j + 1;
+                        } else if (c == '>') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append(">");
+                            pos = j + 1;
+                        } else if (c == '\'') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append("'"); // '
+                            pos = j + 1;
+                        } else if (c == '&') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append("&");
+                            pos = j + 1;
+                        } else if (c == '"') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append("""); // "
+                            pos = j + 1;
+                        }
+                    }
+                }
+                if (pos < len) {
+                    sb.append(s, pos, len);
+                }
+                return sb.toString();
             }
         }
-        return sb.toString();
+        return s;
     }
 
     /**
diff --git a/java/org/apache/jasper/tagplugins/jstl/Util.java b/java/org/apache/jasper/tagplugins/jstl/Util.java
index ca90ed1..faca82b 100644
--- a/java/org/apache/jasper/tagplugins/jstl/Util.java
+++ b/java/org/apache/jasper/tagplugins/jstl/Util.java
@@ -178,11 +178,18 @@ public class Util {
      * 
      * taken from org.apache.taglibs.standard.tag.common.core.Util
      */
-    @SuppressWarnings("null") // escapedBuffer cannot be null
     public static String escapeXml(String buffer) {
+        String result = escapeXml(buffer.toCharArray(), buffer.length());
+        if (result == null) {
+            return buffer;
+        } else {
+            return result;
+        }
+    }
+
+    @SuppressWarnings("null") // escapedBuffer cannot be null
+    public static String escapeXml(char[] arrayBuffer, int length) {
         int start = 0;
-        int length = buffer.length();
-        char[] arrayBuffer = buffer.toCharArray();
         StringBuilder escapedBuffer = null;
         
         for (int i = 0; i < length; i++) {
@@ -206,7 +213,7 @@ public class Util {
         }
         // no xml escaping was necessary
         if (start == 0) {
-            return buffer;
+            return null;
         }
         // add rest of unescaped portion
         if (start < length) {
diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Out.java b/java/org/apache/jasper/tagplugins/jstl/core/Out.java
index 58d3a9e..4fd0dc1 100644
--- a/java/org/apache/jasper/tagplugins/jstl/core/Out.java
+++ b/java/org/apache/jasper/tagplugins/jstl/core/Out.java
@@ -18,8 +18,14 @@
 
 package org.apache.jasper.tagplugins.jstl.core;
 
+import java.io.IOException;
+import java.io.Reader;
+
+import javax.servlet.jsp.JspWriter;
+
 import org.apache.jasper.compiler.tagplugin.TagPlugin;
 import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+import org.apache.jasper.tagplugins.jstl.Util;
 
 
 public final class Out implements TagPlugin {
@@ -35,23 +41,27 @@ public final class Out implements TagPlugin {
         
         //strValName, strEscapeXmlName & strDefName are two variables' name 
         //standing for value, escapeXml and default attribute
+        String strObjectName = ctxt.getTemporaryVariableName();
         String strValName = ctxt.getTemporaryVariableName();
         String strDefName = ctxt.getTemporaryVariableName();
         String strEscapeXmlName = ctxt.getTemporaryVariableName();
-        
+        String strSkipBodyName = ctxt.getTemporaryVariableName();
+
         //according to the tag file, the value attribute is mandatory.
-        ctxt.generateJavaSource("String " + strValName + " = null;");
-        ctxt.generateJavaSource("if(");
-        ctxt.generateAttribute("value");
-        ctxt.generateJavaSource("!=null){");
-        ctxt.generateJavaSource("    " + strValName + " = (");
+        ctxt.generateImport("java.io.Reader");
+        ctxt.generateJavaSource("Object " + strObjectName + "=");
         ctxt.generateAttribute("value");
-        ctxt.generateJavaSource(").toString();");
+        ctxt.generateJavaSource(";");
+        ctxt.generateJavaSource("String " + strValName + "=null;");
+        ctxt.generateJavaSource("if(!(" + strObjectName +
+                " instanceof Reader) && "+ strObjectName + " != null){");
+        ctxt.generateJavaSource(
+                strValName + " = " + strObjectName + ".toString();");
         ctxt.generateJavaSource("}");
         
         //initiate the strDefName with null.
         //if the default has been specified, then assign the value to it;
-        ctxt.generateJavaSource("String " + strDefName + " = null;\n");
+        ctxt.generateJavaSource("String " + strDefName + " = null;");
         if(hasDefault){
             ctxt.generateJavaSource("if(");
             ctxt.generateAttribute("default");
@@ -66,26 +76,54 @@ public final class Out implements TagPlugin {
         //if the escapeXml is specified, assign the value to it;
         ctxt.generateJavaSource("boolean " + strEscapeXmlName + " = true;");
         if(hasEscapeXml){
-            ctxt.generateJavaSource(strEscapeXmlName + " = Boolean.parseBoolean((");
-            ctxt.generateAttribute("default");
-            ctxt.generateJavaSource(").toString());");
+            ctxt.generateJavaSource(strEscapeXmlName + " = ");
+            ctxt.generateAttribute("escapeXml");
+            ctxt.generateJavaSource(";");
         }
         
         //main part. 
-        ctxt.generateJavaSource("if(null != " + strValName +"){");
-        ctxt.generateJavaSource("    if(" + strEscapeXmlName + "){");
-        ctxt.generateJavaSource("        " + strValName + " = org.apache.jasper.tagplugins.jstl.Util.escapeXml(" + strValName + ");");
-        ctxt.generateJavaSource("    }");
-        ctxt.generateJavaSource("    out.write(" + strValName + ");");
-        ctxt.generateJavaSource("}else{");
-        ctxt.generateJavaSource("    if(null != " + strDefName + "){");
-        ctxt.generateJavaSource("        if(" + strEscapeXmlName + "){");
-        ctxt.generateJavaSource("            " + strDefName + " = org.apache.jasper.tagplugins.jstl.Util.escapeXml(" + strDefName + ");");
-        ctxt.generateJavaSource("        }");
-        ctxt.generateJavaSource("        out.write(" + strDefName + ");");
-        ctxt.generateJavaSource("    }else{");
+        ctxt.generateJavaSource(
+                "boolean " + strSkipBodyName + " = " +
+                "org.apache.jasper.tagplugins.jstl.core.Out.output(out, " +
+                strObjectName + ", " + strValName + ", " + strDefName + ", " +
+                strEscapeXmlName + ");");
+        ctxt.generateJavaSource("if(!" + strSkipBodyName + ") {");
         ctxt.generateBody();
-        ctxt.generateJavaSource("    }");
-        ctxt.generateJavaSource("}");   
+        ctxt.generateJavaSource("}");
+    }
+
+    public static boolean output(JspWriter out, Object input, String value,
+            String defaultValue, boolean escapeXml) throws IOException {
+        if (input instanceof Reader) {
+            char[] buffer = new char[8096];
+            int read = 0;
+            while (read != -1) {
+                read = ((Reader) input).read(buffer);
+                if (read != -1) {
+                    if (escapeXml) {
+                        String escaped = Util.escapeXml(buffer, read);
+                        if (escaped == null) {
+                            out.write(buffer, 0, read);
+                        } else {
+                            out.print(escaped);
+                        }
+                    } else {
+                        out.write(buffer, 0, read);
+                    }
+                }
+            }
+            return true;
+        } else {
+            String v = value != null ? value : defaultValue;
+            if (v != null) {
+                if(escapeXml){
+                    v = Util.escapeXml(v);
+                }
+                out.write(v);
+                return true;
+            } else {
+                return false;
+            }
+        }
     }
 }
diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Set.java b/java/org/apache/jasper/tagplugins/jstl/core/Set.java
index c6b5d84..c1076d2 100644
--- a/java/org/apache/jasper/tagplugins/jstl/core/Set.java
+++ b/java/org/apache/jasper/tagplugins/jstl/core/Set.java
@@ -70,14 +70,20 @@ public class Set implements TagPlugin {
         
         //if the attribute var has been specified then assign the result to the var;
         if(hasVar){
+            String jspCtxt = null;
+            if (ctxt.isTagFile()) {
+                jspCtxt = "this.getJspContext()";
+            } else {
+                jspCtxt = "_jspx_page_context";
+            }
             String strVar = ctxt.getConstantAttribute("var");
             ctxt.generateJavaSource("if(null != " + resultName + "){");
-            ctxt.generateJavaSource("    pageContext.setAttribute(\"" + strVar + "\"," + resultName + "," + iScope + ");");
+            ctxt.generateJavaSource("    " + jspCtxt + ".setAttribute(\"" + strVar + "\"," + resultName + "," + iScope + ");");
             ctxt.generateJavaSource("} else {");
             if(hasScope){
-                ctxt.generateJavaSource("    pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");");
+                ctxt.generateJavaSource("    " + jspCtxt + ".removeAttribute(\"" + strVar + "\"," + iScope + ");");
             }else{
-                ctxt.generateJavaSource("    pageContext.removeAttribute(\"" + strVar + "\");");
+                ctxt.generateJavaSource("    " + jspCtxt + ".removeAttribute(\"" + strVar + "\");");
             }
             ctxt.generateJavaSource("}");
             
diff --git a/java/org/apache/juli/DateFormatCache.java b/java/org/apache/juli/DateFormatCache.java
index cead1f6..0c6e404 100644
--- a/java/org/apache/juli/DateFormatCache.java
+++ b/java/org/apache/juli/DateFormatCache.java
@@ -41,7 +41,7 @@ import java.util.TimeZone;
  * <p>The cache can be created with a parent cache to build a cache hierarchy.
  * Access to the parent cache is threadsafe.</p>
  *
- * @version $Id: DateFormatCache.java 1185021 2011-10-17 06:23:02Z rjung $
+ * @version $Id: DateFormatCache.java 1402624 2012-10-26 19:27:06Z markt $
  */
 
 public class DateFormatCache {
@@ -101,14 +101,14 @@ public class DateFormatCache {
     private class Cache {
 
         /* Second formatted in most recent invocation */
-        private long previousSeconds = 0L;
+        private long previousSeconds = Long.MIN_VALUE;
         /* Formatted timestamp generated in most recent invocation */
         private String previousFormat = "";
 
         /* First second contained in cache */
-        private long first = 0L;
+        private long first = Long.MIN_VALUE;
         /* Last second contained in cache */
-        private long last = 0L;
+        private long last = Long.MIN_VALUE;
         /* Index of "first" in the cyclic cache */
         private int offset = 0;
         /* Helper object to be able to call SimpleDateFormat.format(). */
@@ -165,14 +165,16 @@ public class DateFormatCache {
                 for (int i = 1; i < seconds - last; i++) {
                     cache[(index + cacheSize - i) % cacheSize] = null;
                 }
-                first = seconds - cacheSize;
+                first = seconds - (cacheSize - 1);
                 last = seconds;
+                offset = (index + 1) % cacheSize;
             } else if (seconds < first) {
                 for (int i = 1; i < first - seconds; i++) {
                     cache[(index + i) % cacheSize] = null;
                 }
                 first = seconds;
-                last = seconds + cacheSize;
+                last = seconds + (cacheSize - 1);
+                offset = index;
             }
 
             /* Last step: format new timestamp either using
diff --git a/java/org/apache/naming/SelectorContext.java b/java/org/apache/naming/SelectorContext.java
index f339859..8f3db1d 100644
--- a/java/org/apache/naming/SelectorContext.java
+++ b/java/org/apache/naming/SelectorContext.java
@@ -32,7 +32,7 @@ import javax.naming.NamingException;
  * Catalina JNDI Context implementation.
  *
  * @author Remy Maucherat
- * @version $Id: SelectorContext.java 1304471 2012-03-23 16:41:38Z kkolinko $
+ * @version $Id: SelectorContext.java 1373051 2012-08-14 19:47:38Z markt $
  */
 
 public class SelectorContext implements Context {
@@ -168,7 +168,7 @@ public class SelectorContext implements Context {
      * @param obj the object to bind; possibly null
      * @exception javax.naming.NameAlreadyBoundException if name is already
      * bound
-     * @exception javax.naming.InvalidAttributesException if object did not
+     * @exception javax.naming.directory.InvalidAttributesException if object did not
      * supply all mandatory attributes
      * @exception NamingException if a naming exception is encountered
      */
@@ -186,7 +186,7 @@ public class SelectorContext implements Context {
      * @param obj the object to bind; possibly null
      * @exception javax.naming.NameAlreadyBoundException if name is already
      * bound
-     * @exception javax.naming.InvalidAttributesException if object did not
+     * @exception javax.naming.directory.InvalidAttributesException if object did not
      * supply all mandatory attributes
      * @exception NamingException if a naming exception is encountered
      */
@@ -208,7 +208,7 @@ public class SelectorContext implements Context {
      *
      * @param name the name to bind; may not be empty
      * @param obj the object to bind; possibly null
-     * @exception javax.naming.InvalidAttributesException if object did not
+     * @exception javax.naming.directory.InvalidAttributesException if object did not
      * supply all mandatory attributes
      * @exception NamingException if a naming exception is encountered
      */
@@ -224,7 +224,7 @@ public class SelectorContext implements Context {
      *
      * @param name the name to bind; may not be empty
      * @param obj the object to bind; possibly null
-     * @exception javax.naming.InvalidAttributesException if object did not
+     * @exception javax.naming.directory.InvalidAttributesException if object did not
      * supply all mandatory attributes
      * @exception NamingException if a naming exception is encountered
      */
@@ -461,7 +461,7 @@ public class SelectorContext implements Context {
      * @return the newly created context
      * @exception javax.naming.NameAlreadyBoundException if name is already
      * bound
-     * @exception javax.naming.InvalidAttributesException if creation of the
+     * @exception javax.naming.directory.InvalidAttributesException if creation of the
      * sub-context requires specification of mandatory attributes
      * @exception NamingException if a naming exception is encountered
      */
@@ -479,7 +479,7 @@ public class SelectorContext implements Context {
      * @return the newly created context
      * @exception javax.naming.NameAlreadyBoundException if name is already
      * bound
-     * @exception javax.naming.InvalidAttributesException if creation of the
+     * @exception javax.naming.directory.InvalidAttributesException if creation of the
      * sub-context requires specification of mandatory attributes
      * @exception NamingException if a naming exception is encountered
      */
diff --git a/java/org/apache/naming/resources/BaseDirContext.java b/java/org/apache/naming/resources/BaseDirContext.java
index 120fba6..e7e6f91 100644
--- a/java/org/apache/naming/resources/BaseDirContext.java
+++ b/java/org/apache/naming/resources/BaseDirContext.java
@@ -48,6 +48,7 @@ import javax.naming.directory.SearchResult;
 
 import org.apache.naming.NameParserImpl;
 import org.apache.naming.NamingContextBindingsEnumeration;
+import org.apache.naming.NamingContextEnumeration;
 import org.apache.naming.NamingEntry;
 import org.apache.naming.StringManager;
 
@@ -55,7 +56,7 @@ import org.apache.naming.StringManager;
  * Directory Context implementation helper class.
  *
  * @author Remy Maucherat
- * @version $Id: BaseDirContext.java 1347095 2012-06-06 20:17:43Z schultz $
+ * @version $Id: BaseDirContext.java 1409127 2012-11-14 09:53:04Z kkolinko $
  */
 
 public abstract class BaseDirContext implements DirContext {
@@ -674,8 +675,44 @@ public abstract class BaseDirContext implements DirContext {
      * @exception NamingException if a naming exception is encountered
      */
     @Override
-    public abstract NamingEnumeration<NameClassPair> list(String name)
-        throws NamingException;
+    public NamingEnumeration<NameClassPair> list(String name)
+        throws NamingException {
+
+        if (!aliases.isEmpty()) {
+            AliasResult result = findAlias(name);
+            if (result.dirContext != null) {
+                return result.dirContext.list(result.aliasName);
+            }
+        }
+
+        // Next do a standard lookup
+        List<NamingEntry> bindings = doListBindings(name);
+
+        // Check the alternate locations
+        List<NamingEntry> altBindings = null;
+
+        for (DirContext altDirContext : altDirContexts) {
+            if (altDirContext instanceof BaseDirContext) {
+                altBindings = ((BaseDirContext) altDirContext).doListBindings(
+                        "/META-INF/resources" + name);
+            }
+            if (altBindings != null) {
+                if (bindings == null) {
+                    bindings = altBindings;
+                } else {
+                    bindings.addAll(altBindings);
+                }
+            }
+        }
+
+        if (bindings != null) {
+            return new NamingContextEnumeration(bindings.iterator());
+        }
+
+        // Really not found
+        throw new NameNotFoundException(
+                sm.getString("resources.notFound", name));
+    }
 
 
     /**
diff --git a/java/org/apache/naming/resources/FileDirContext.java b/java/org/apache/naming/resources/FileDirContext.java
index 7e28948..bce8e3c 100644
--- a/java/org/apache/naming/resources/FileDirContext.java
+++ b/java/org/apache/naming/resources/FileDirContext.java
@@ -30,7 +30,6 @@ import java.util.Hashtable;
 import java.util.List;
 
 import javax.naming.NameAlreadyBoundException;
-import javax.naming.NameClassPair;
 import javax.naming.NameNotFoundException;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
@@ -41,7 +40,6 @@ import javax.naming.directory.ModificationItem;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 
-import org.apache.naming.NamingContextEnumeration;
 import org.apache.naming.NamingEntry;
 import org.apache.tomcat.util.http.RequestUtil;
 
@@ -49,7 +47,7 @@ import org.apache.tomcat.util.http.RequestUtil;
  * Filesystem Directory Context implementation helper class.
  *
  * @author Remy Maucherat
- * @version $Id: FileDirContext.java 1239053 2012-02-01 10:52:00Z markt $
+ * @version $Id: FileDirContext.java 1392099 2012-09-30 19:48:36Z markt $
  */
 
 public class FileDirContext extends BaseDirContext {
@@ -279,34 +277,6 @@ public class FileDirContext extends BaseDirContext {
 
 
     /**
-     * Enumerates the names bound in the named context, along with the class
-     * names of objects bound to them. The contents of any subcontexts are
-     * not included.
-     * <p>
-     * If a binding is added to or removed from this context, its effect on
-     * an enumeration previously returned is undefined.
-     *
-     * @param name the name of the context to list
-     * @return an enumeration of the names and class names of the bindings in
-     * this context. Each element of the enumeration is of type NameClassPair.
-     * @exception NamingException if a naming exception is encountered
-     */
-    @Override
-    public NamingEnumeration<NameClassPair> list(String name)
-        throws NamingException {
-
-        File file = file(name);
-
-        if (file == null)
-            throw new NameNotFoundException
-                (sm.getString("resources.notFound", name));
-
-        return new NamingContextEnumeration(list(file).iterator());
-
-    }
-
-
-    /**
      * Enumerates the names bound in the named context, along with the
      * objects bound to them. The contents of any subcontexts are not
      * included.
@@ -872,7 +842,7 @@ public class FileDirContext extends BaseDirContext {
             Object object = null;
             if (currentFile.isDirectory()) {
                 FileDirContext tempContext = new FileDirContext(env);
-                tempContext.setDocBase(file.getPath());
+                tempContext.setDocBase(currentFile.getPath());
                 tempContext.setAllowLinking(getAllowLinking());
                 object = tempContext;
             } else {
diff --git a/java/org/apache/naming/resources/VirtualDirContext.java b/java/org/apache/naming/resources/VirtualDirContext.java
index 39942af..5e64b2d 100644
--- a/java/org/apache/naming/resources/VirtualDirContext.java
+++ b/java/org/apache/naming/resources/VirtualDirContext.java
@@ -56,7 +56,7 @@ import org.apache.naming.NamingEntry;
  *
  *
  * @author Fabrizio Giustina
- * @version $Id: VirtualDirContext.java 1307600 2012-03-30 20:33:27Z kkolinko $
+ * @version $Id: VirtualDirContext.java 1371816 2012-08-10 19:54:55Z markt $
  */
 public class VirtualDirContext extends FileDirContext {
     private String extraResourcePaths = "";
@@ -296,4 +296,13 @@ public class VirtualDirContext extends FileDirContext {
         return retSuper;
     }
 
+    @Override
+    protected String doGetRealPath(String path) {
+        File file = file(path);
+        if (null != file) {
+            return file.getAbsolutePath();
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/java/org/apache/naming/resources/WARDirContext.java b/java/org/apache/naming/resources/WARDirContext.java
index be903e3..8733a3f 100644
--- a/java/org/apache/naming/resources/WARDirContext.java
+++ b/java/org/apache/naming/resources/WARDirContext.java
@@ -34,8 +34,6 @@ import java.util.zip.ZipFile;
 import javax.naming.CompositeName;
 import javax.naming.InvalidNameException;
 import javax.naming.Name;
-import javax.naming.NameClassPair;
-import javax.naming.NameNotFoundException;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.OperationNotSupportedException;
@@ -45,14 +43,13 @@ import javax.naming.directory.ModificationItem;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 
-import org.apache.naming.NamingContextEnumeration;
 import org.apache.naming.NamingEntry;
 
 /**
  * WAR Directory Context implementation.
  *
  * @author Remy Maucherat
- * @version $Id: WARDirContext.java 1081987 2011-03-15 23:05:53Z markt $
+ * @version $Id: WARDirContext.java 1392099 2012-09-30 19:48:36Z markt $
  */
 
 public class WARDirContext extends BaseDirContext {
@@ -271,52 +268,6 @@ public class WARDirContext extends BaseDirContext {
 
 
     /**
-     * Enumerates the names bound in the named context, along with the class 
-     * names of objects bound to them. The contents of any subcontexts are 
-     * not included.
-     * <p>
-     * If a binding is added to or removed from this context, its effect on 
-     * an enumeration previously returned is undefined.
-     * 
-     * @param name the name of the context to list
-     * @return an enumeration of the names and class names of the bindings in 
-     * this context. Each element of the enumeration is of type NameClassPair.
-     * @exception NamingException if a naming exception is encountered
-     */
-    @Override
-    public NamingEnumeration<NameClassPair> list(String name)
-        throws NamingException {
-        return list(getEscapedJndiName(name));
-    }
-
-
-    /**
-     * Enumerates the names bound in the named context, along with the class 
-     * names of objects bound to them. The contents of any subcontexts are 
-     * not included.
-     * <p>
-     * If a binding is added to or removed from this context, its effect on 
-     * an enumeration previously returned is undefined.
-     * 
-     * @param name the name of the context to list
-     * @return an enumeration of the names and class names of the bindings in 
-     * this context. Each element of the enumeration is of type NameClassPair.
-     * @exception NamingException if a naming exception is encountered
-     */
-    @Override
-    public NamingEnumeration<NameClassPair> list(Name name)
-        throws NamingException {
-        if (name.isEmpty())
-            return new NamingContextEnumeration(list(entries).iterator());
-        Entry entry = treeLookup(name);
-        if (entry == null)
-            throw new NameNotFoundException
-                (sm.getString("resources.notFound", name));
-        return new NamingContextEnumeration(list(entry).iterator());
-    }
-
-
-    /**
      * Enumerates the names bound in the named context, along with the 
      * objects bound to them. The contents of any subcontexts are not 
      * included.
diff --git a/java/org/apache/tomcat/util/bcel/Constants.java b/java/org/apache/tomcat/util/bcel/Constants.java
index 27605eb..57ffed8 100644
--- a/java/org/apache/tomcat/util/bcel/Constants.java
+++ b/java/org/apache/tomcat/util/bcel/Constants.java
@@ -20,7 +20,7 @@ package org.apache.tomcat.util.bcel;
 /**
  * Constants for the project, mostly defined in the JVM specification.
  *
- * @version $Id: Constants.java 1237336 2012-01-29 16:43:45Z markt $
+ * @version $Id: Constants.java 1377534 2012-08-26 22:26:10Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  */
 public interface Constants {
@@ -94,13 +94,23 @@ public interface Constants {
   /** Marks a constant pool entry as a name and type.  */
   public static final byte CONSTANT_NameAndType        = 12;
 
+  /** Marks a constant pool entry as a Method Handle.  */
+  public static final byte CONSTANT_MethodHandle       = 15;
+
+  /** Marks a constant pool entry as a Method Type.    */
+  public static final byte CONSTANT_MethodType         = 16;
+
+  /** Marks a constant pool entry as an Invoke Dynamic */
+  public static final byte CONSTANT_InvokeDynamic      = 18;
+
   /** The names of the types of entries in a constant pool. */
   public static final String[] CONSTANT_NAMES = {
     "", "CONSTANT_Utf8", "", "CONSTANT_Integer",
     "CONSTANT_Float", "CONSTANT_Long", "CONSTANT_Double",
     "CONSTANT_Class", "CONSTANT_String", "CONSTANT_Fieldref",
     "CONSTANT_Methodref", "CONSTANT_InterfaceMethodref",
-    "CONSTANT_NameAndType" };
+    "CONSTANT_NameAndType", "CONSTANT_MethodHandle",
+    "CONSTANT_MethodType", "CONSTANT_InvokeDynamic" };
   
   /** Java VM opcode.
    * @see <a href="http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc.html">Opcode definitions in The Java Virtual Machine Specification</a> */
diff --git a/java/org/apache/tomcat/util/bcel/classfile/AnnotationDefault.java b/java/org/apache/tomcat/util/bcel/classfile/AnnotationDefault.java
index 251a57d..3299cd5 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/AnnotationDefault.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/AnnotationDefault.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -86,11 +85,4 @@ public class AnnotationDefault extends Attribute
     {
         throw new RuntimeException("Not implemented yet!");
     }
-
-    @Override
-    public final void dump(DataOutputStream dos) throws IOException
-    {
-      super.dump(dos);
-      default_value.dump(dos);
-    }
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/Attribute.java b/java/org/apache/tomcat/util/bcel/classfile/Attribute.java
index 487bd3a..99f44c4 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/Attribute.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/Attribute.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.HashMap;
@@ -34,7 +33,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * <em>Synthetic</em> attributes are supported. The <em>Unknown</em>
  * attribute stands for non-standard-attributes.
  * 
- * @version $Id: Attribute.java 992416 2010-09-03 18:50:57Z markt $
+ * @version $Id: Attribute.java 1377533 2012-08-26 22:22:59Z markt $
  * @author <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see ConstantValue
  * @see SourceFile
@@ -69,19 +68,6 @@ public abstract class Attribute implements Cloneable, Serializable
         this.constant_pool = constant_pool;
     }
 
-    /**
-     * Dump attribute to file stream in binary format.
-     * 
-     * @param file
-     *            Output file stream
-     * @throws IOException
-     */
-    public void dump(DataOutputStream file) throws IOException
-    {
-        file.writeShort(name_index);
-        file.writeInt(length);
-    }
-
     private static final Map<String,AttributeReader> readers =
             new HashMap<String,AttributeReader>();
 
diff --git a/java/org/apache/tomcat/util/bcel/classfile/Code.java b/java/org/apache/tomcat/util/bcel/classfile/Code.java
index f43f421..654a143 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/Code.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/Code.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -35,7 +34,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * is used for debugging purposes and <em>LocalVariableTable</em> which 
  * contains information about the local variables.
  *
- * @version $Id: Code.java 1181133 2011-10-10 18:49:14Z markt $
+ * @version $Id: Code.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Attribute
  * @see     CodeException
@@ -115,30 +114,6 @@ public final class Code extends Attribute {
 
 
     /**
-     * Dump code attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(max_stack);
-        file.writeShort(max_locals);
-        file.writeInt(code_length);
-        file.write(code, 0, code_length);
-        file.writeShort(exception_table_length);
-        for (int i = 0; i < exception_table_length; i++) {
-            exception_table[i].dump(file);
-        }
-        file.writeShort(attributes_count);
-        for (int i = 0; i < attributes_count; i++) {
-            attributes[i].dump(file);
-        }
-    }
-
-
-    /**
      * @return LocalVariableTable of Code, if it has one
      */
     public LocalVariableTable getLocalVariableTable() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/Constant.java b/java/org/apache/tomcat/util/bcel/classfile/Constant.java
index ee07467..494befb 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/Constant.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/Constant.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.Serializable;
 
@@ -30,7 +29,7 @@ import org.apache.tomcat.util.bcel.util.BCELComparator;
  * in the constant pool of a class file. The classes keep closely to
  * the JVM specification.
  *
- * @version $Id: Constant.java 992409 2010-09-03 18:35:59Z markt $
+ * @version $Id: Constant.java 1377534 2012-08-26 22:26:10Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  */
 public abstract class Constant implements Cloneable, Serializable {
@@ -68,9 +67,6 @@ public abstract class Constant implements Cloneable, Serializable {
     }
 
 
-    public abstract void dump( DataOutputStream file ) throws IOException;
-
-
     /**
      * @return Tag of constant, i.e., its type. No setTag() method to avoid
      * confusion.
@@ -127,6 +123,12 @@ public abstract class Constant implements Cloneable, Serializable {
                 return new ConstantNameAndType(file);
             case Constants.CONSTANT_Utf8:
                 return new ConstantUtf8(file);
+            case Constants.CONSTANT_MethodHandle:
+                return new ConstantMethodHandle(file);
+            case Constants.CONSTANT_MethodType:
+                return new ConstantMethodType(file);
+            case Constants.CONSTANT_InvokeDynamic:
+                return new ConstantInvokeDynamic(file);
             default:
                 throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
         }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantCP.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantCP.java
index 3a0e049..30d497c 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantCP.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantCP.java
@@ -18,13 +18,12 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 /** 
  * Abstract super class for Fieldref and Methodref constants.
  *
- * @version $Id: ConstantCP.java 992409 2010-09-03 18:35:59Z markt $
+ * @version $Id: ConstantCP.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     ConstantFieldref
  * @see     ConstantMethodref
@@ -62,20 +61,6 @@ public abstract class ConstantCP extends Constant {
 
 
     /** 
-     * Dump constant field reference to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeShort(class_index);
-        file.writeShort(name_and_type_index);
-    }
-
-
-    /**
      * @return Reference (index) to class this field or method belongs to.
      */
     public final int getClassIndex() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java
index 853b7a9..ea0910f 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -28,7 +27,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class 
  * and represents a reference to a (external) class.
  *
- * @version $Id: ConstantClass.java 1181135 2011-10-10 18:51:44Z markt $
+ * @version $Id: ConstantClass.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Constant
  */
@@ -60,19 +59,6 @@ public final class ConstantClass extends Constant {
 
 
     /** 
-     * Dump constant class to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeShort(name_index);
-    }
-
-
-    /**
      * @return Name index in constant pool of class name.
      */
     public final int getNameIndex() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java
index 7db4091..6ba0d78 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -28,7 +27,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class 
  * and represents a reference to a Double object.
  *
- * @version $Id: ConstantDouble.java 1181135 2011-10-10 18:51:44Z markt $
+ * @version $Id: ConstantDouble.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Constant
  */
@@ -59,19 +58,6 @@ public final class ConstantDouble extends Constant {
 
 
     /**
-     * Dump constant double to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeDouble(bytes);
-    }
-
-
-    /**
      * @return data, i.e., 8 bytes.
      */
     public final double getBytes() {
@@ -86,6 +72,4 @@ public final class ConstantDouble extends Constant {
     public final String toString() {
         return super.toString() + "(bytes = " + bytes + ")";
     }
-
-
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java
index b50ca9e..aa6de2e 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -28,7 +27,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class 
  * and represents a reference to a float object.
  *
- * @version $Id: ConstantFloat.java 1181135 2011-10-10 18:51:44Z markt $
+ * @version $Id: ConstantFloat.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Constant
  */
@@ -59,19 +58,6 @@ public final class ConstantFloat extends Constant {
 
     
     /**
-     * Dump constant float to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeFloat(bytes);
-    }
-
-
-    /**
      * @return data, i.e., 4 bytes.
      */
     public final float getBytes() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java
index 2dab682..10e7762 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -28,7 +27,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class 
  * and represents a reference to an int object.
  *
- * @version $Id: ConstantInteger.java 1181135 2011-10-10 18:51:44Z markt $
+ * @version $Id: ConstantInteger.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Constant
  */
@@ -59,19 +58,6 @@ public final class ConstantInteger extends Constant {
 
 
     /**
-     * Dump constant integer to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeInt(bytes);
-    }
-
-
-    /**
      * @return data, i.e., 4 bytes.
      */
     public final int getBytes() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantInvokeDynamic.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantInvokeDynamic.java
new file mode 100644
index 0000000..bc03306
--- /dev/null
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantInvokeDynamic.java
@@ -0,0 +1,95 @@
+/*
+ * 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.tomcat.util.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.tomcat.util.bcel.Constants;
+
+/**
+ * This class is derived from the abstract
+ * <A HREF="org.apache.bcel.classfile.Constant.html">Constant</A> class
+ * and represents a reference to a invoke dynamic.
+ *
+ * @see     Constant
+ */
+public final class ConstantInvokeDynamic extends Constant {
+
+    private static final long serialVersionUID = 4310367359017396174L;
+    private int bootstrap_method_attr_index;
+    private int name_and_type_index;
+
+
+    /**
+     * Initialize from another object.
+     */
+    public ConstantInvokeDynamic(ConstantInvokeDynamic c) {
+        this(c.getBootstrapMethodAttrIndex(), c.getNameAndTypeIndex());
+    }
+
+
+    /**
+     * Initialize instance from file data.
+     *
+     * @param file Input stream
+     * @throws IOException
+     */
+    ConstantInvokeDynamic(DataInput file) throws IOException {
+        this(file.readUnsignedShort(), file.readUnsignedShort());
+    }
+
+
+    public ConstantInvokeDynamic(int bootstrap_method_attr_index,
+            int name_and_type_index) {
+        super(Constants.CONSTANT_InvokeDynamic);
+        this.bootstrap_method_attr_index = bootstrap_method_attr_index;
+        this.name_and_type_index = name_and_type_index;
+    }
+
+
+    public int getBootstrapMethodAttrIndex() {
+        return bootstrap_method_attr_index;
+    }
+
+
+    public void setBootstrapMethodAttrIndex(int bootstrap_method_attr_index) {
+        this.bootstrap_method_attr_index = bootstrap_method_attr_index;
+    }
+
+
+    public int getNameAndTypeIndex() {
+        return name_and_type_index;
+    }
+
+
+    public void setNameAndTypeIndex(int name_and_type_index) {
+        this.name_and_type_index = name_and_type_index;
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        return super.toString() + "(bootstrap_method_attr_index = " +
+                bootstrap_method_attr_index + ", name_and_type_index = " +
+                name_and_type_index + ")";
+    }
+}
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java
index 93d91b3..e2bd60a 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -28,7 +27,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class 
  * and represents a reference to a long object.
  *
- * @version $Id: ConstantLong.java 1181135 2011-10-10 18:51:44Z markt $
+ * @version $Id: ConstantLong.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Constant
  */
@@ -59,19 +58,6 @@ public final class ConstantLong extends Constant {
 
 
     /**
-     * Dump constant long to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeLong(bytes);
-    }
-
-
-    /**
      * @return data, i.e., 8 bytes.
      */
     public final long getBytes() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodHandle.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodHandle.java
new file mode 100644
index 0000000..9ba58f3
--- /dev/null
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodHandle.java
@@ -0,0 +1,93 @@
+/*
+ * 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.tomcat.util.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.tomcat.util.bcel.Constants;
+
+/**
+ * This class is derived from the abstract
+ * <A HREF="org.apache.bcel.classfile.Constant.html">Constant</A> class
+ * and represents a reference to a method handle.
+ *
+ * @see     Constant
+ */
+public final class ConstantMethodHandle extends Constant {
+
+    private static final long serialVersionUID = -7875124116920198044L;
+    private int reference_kind;
+    private int reference_index;
+
+
+    /**
+     * Initialize from another object.
+     */
+    public ConstantMethodHandle(ConstantMethodHandle c) {
+        this(c.getReferenceKind(), c.getReferenceIndex());
+    }
+
+
+    /**
+     * Initialize instance from file data.
+     *
+     * @param file Input stream
+     * @throws IOException
+     */
+    ConstantMethodHandle(DataInput file) throws IOException {
+        this(file.readUnsignedByte(), file.readUnsignedShort());
+    }
+
+
+    public ConstantMethodHandle(int reference_kind, int reference_index) {
+        super(Constants.CONSTANT_MethodHandle);
+        this.reference_kind = reference_kind;
+        this.reference_index = reference_index;
+    }
+
+
+    public int getReferenceKind() {
+        return reference_kind;
+    }
+
+
+    public void setReferenceKind(int reference_kind) {
+        this.reference_kind = reference_kind;
+    }
+
+
+    public int getReferenceIndex() {
+        return reference_index;
+    }
+
+
+    public void setReferenceIndex(int reference_index) {
+        this.reference_index = reference_index;
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        return super.toString() + "(reference_kind = " + reference_kind +
+                ", reference_index = " + reference_index + ")";
+    }
+}
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodType.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodType.java
new file mode 100644
index 0000000..3280488
--- /dev/null
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodType.java
@@ -0,0 +1,80 @@
+/*
+ * 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.tomcat.util.bcel.classfile;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.tomcat.util.bcel.Constants;
+
+/**
+ * This class is derived from the abstract
+ * <A HREF="org.apache.bcel.classfile.Constant.html">Constant</A> class
+ * and represents a reference to a method type.
+ *
+ * @see     Constant
+ */
+public final class ConstantMethodType extends Constant {
+
+    private static final long serialVersionUID = 6750768220616618881L;
+    private int descriptor_index;
+
+
+    /**
+     * Initialize from another object.
+     */
+    public ConstantMethodType(ConstantMethodType c) {
+        this(c.getDescriptorIndex());
+    }
+
+
+    /**
+     * Initialize instance from file data.
+     *
+     * @param file Input stream
+     * @throws IOException
+     */
+    ConstantMethodType(DataInput file) throws IOException {
+        this(file.readUnsignedShort());
+    }
+
+
+    public ConstantMethodType(int descriptor_index) {
+        super(Constants.CONSTANT_MethodType);
+        this.descriptor_index = descriptor_index;
+    }
+
+
+    public int getDescriptorIndex() {
+        return descriptor_index;
+    }
+
+
+    public void setDescriptorIndex(int descriptor_index) {
+        this.descriptor_index = descriptor_index;
+    }
+
+
+    /**
+     * @return String representation
+     */
+    @Override
+    public final String toString() {
+        return super.toString() + "(descriptor_index = " + descriptor_index + ")";
+    }
+}
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantNameAndType.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantNameAndType.java
index 76743ab..8c21824 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantNameAndType.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantNameAndType.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -29,7 +28,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * and represents a reference to the name and signature
  * of a field or method.
  *
- * @version $Id: ConstantNameAndType.java 992409 2010-09-03 18:35:59Z markt $
+ * @version $Id: ConstantNameAndType.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Constant
  */
@@ -63,20 +62,6 @@ public final class ConstantNameAndType extends Constant {
 
 
     /**
-     * Dump name and signature index to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeShort(name_index);
-        file.writeShort(signature_index);
-    }
-
-
-    /**
      * @return Name index in constant pool of field/method name.
      */
     public final int getNameIndex() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantString.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantString.java
index 8fb0467..9afa399 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantString.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantString.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -28,7 +27,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class 
  * and represents a reference to a String object.
  *
- * @version $Id: ConstantString.java 1181135 2011-10-10 18:51:44Z markt $
+ * @version $Id: ConstantString.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Constant
  */
@@ -59,19 +58,6 @@ public final class ConstantString extends Constant {
 
 
     /**
-     * Dump constant field reference to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeShort(string_index);
-    }
-
-
-    /**
      * @return Index in constant pool of the string (ConstantUtf8).
      */
     public final int getStringIndex() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantUtf8.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantUtf8.java
index ce0ae8f..518c21b 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantUtf8.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantUtf8.java
@@ -17,7 +17,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -27,7 +26,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * <A HREF="org.apache.tomcat.util.bcel.classfile.Constant.html">Constant</A> class 
  * and represents a reference to a Utf8 encoded string.
  *
- * @version $Id: ConstantUtf8.java 1057670 2011-01-11 14:52:05Z markt $
+ * @version $Id: ConstantUtf8.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Constant
  */
@@ -50,19 +49,6 @@ public final class ConstantUtf8 extends Constant {
 
 
     /**
-     * Dump String in Utf8 format to file stream.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        file.writeByte(tag);
-        file.writeUTF(bytes);
-    }
-
-
-    /**
      * @return Data converted to string.
      */
     public final String getBytes() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantValue.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantValue.java
index a76268a..276d02b 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantValue.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantValue.java
@@ -17,7 +17,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -27,7 +26,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * value, i.e., a default value for initializing a class field.
  * This class is instantiated by the <em>Attribute.readAttribute()</em> method.
  *
- * @version $Id: ConstantValue.java 1057670 2011-01-11 14:52:05Z markt $
+ * @version $Id: ConstantValue.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Attribute
  */
@@ -65,19 +64,6 @@ public final class ConstantValue extends Attribute {
 
 
     /**
-     * Dump constant value attribute to file stream on binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(constantvalue_index);
-    }
-
-
-    /**
      * @return String representation of constant value.
      */
     @Override
diff --git a/java/org/apache/tomcat/util/bcel/classfile/Deprecated.java b/java/org/apache/tomcat/util/bcel/classfile/Deprecated.java
index 3c8ce15..039b7f1 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/Deprecated.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/Deprecated.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -28,7 +27,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * deprecated method.
  * It is instantiated from the <em>Attribute.readAttribute()</em> method.
  *
- * @version $Id: Deprecated.java 1057670 2011-01-11 14:52:05Z markt $
+ * @version $Id: Deprecated.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Attribute
  */
@@ -70,21 +69,6 @@ public final class Deprecated extends Attribute {
 
 
     /**
-     * Dump source file attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        if (length > 0) {
-            file.write(bytes, 0, length);
-        }
-    }
-
-
-    /**
      * @return attribute name
      */
     @Override
diff --git a/java/org/apache/tomcat/util/bcel/classfile/EnclosingMethod.java b/java/org/apache/tomcat/util/bcel/classfile/EnclosingMethod.java
index 4592923..679faae 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/EnclosingMethod.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/EnclosingMethod.java
@@ -17,7 +17,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -30,42 +29,18 @@ public class EnclosingMethod extends Attribute {
     
     private static final long serialVersionUID = 6755214228300933233L;
 
-    // Pointer to the CONSTANT_Class_info structure representing the 
-    // innermost class that encloses the declaration of the current class.
-    private int classIndex;
-    
-    // If the current class is not immediately enclosed by a method or 
-    // constructor, then the value of the method_index item must be zero.  
-    // Otherwise, the value of the  method_index item must point to a 
-    // CONSTANT_NameAndType_info structure representing the name and the 
-    // type of a method in the class referenced by the class we point 
-    // to in the class_index.  *It is the compiler responsibility* to 
-    // ensure that the method identified by this index is the closest 
-    // lexically enclosing method that includes the local/anonymous class.
-    private int methodIndex;
-
     // Ctors - and code to read an attribute in.
-    public EnclosingMethod(int nameIndex, int len, DataInputStream dis, ConstantPool cpool) throws IOException {
-        this(nameIndex, len, dis.readUnsignedShort(), dis.readUnsignedShort(), cpool);
-    }
-
-    private EnclosingMethod(int nameIndex, int len, int classIdx,int methodIdx, ConstantPool cpool) {
+    public EnclosingMethod(int nameIndex, int len, DataInputStream dis,
+            ConstantPool cpool) throws IOException {
         super(Constants.ATTR_ENCLOSING_METHOD, nameIndex, len, cpool);
-        classIndex  = classIdx;
-        methodIndex = methodIdx;
+        // Unused class index
+        dis.readUnsignedShort();
+        // Unused method index
+        dis.readUnsignedShort();
     }
 
     @Override
     public Attribute copy(ConstantPool constant_pool) {
         throw new RuntimeException("Not implemented yet!");
-        // is this next line sufficient?
-        // return (EnclosingMethod)clone();
     }
-    
-    @Override
-    public final void dump(DataOutputStream file) throws IOException {
-        super.dump(file);
-        file.writeShort(classIndex);
-        file.writeShort(methodIndex);
-    }    
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ExceptionTable.java b/java/org/apache/tomcat/util/bcel/classfile/ExceptionTable.java
index 84e17d9..e3e6286 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ExceptionTable.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ExceptionTable.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -31,7 +30,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * attribute using the name <em>Exceptions</em> (which is inconsistent
  * with the other classes).
  *
- * @version $Id: ExceptionTable.java 1181133 2011-10-10 18:49:14Z markt $
+ * @version $Id: ExceptionTable.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Code
  */
@@ -75,22 +74,6 @@ public final class ExceptionTable extends Attribute {
 
 
     /**
-     * Dump exceptions attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(number_of_exceptions);
-        for (int i = 0; i < number_of_exceptions; i++) {
-            file.writeShort(exception_index_table[i]);
-        }
-    }
-
-
-    /**
      * @param exception_index_table the list of exception indexes
      * Also redefines number_of_exceptions according to table length.
      */
diff --git a/java/org/apache/tomcat/util/bcel/classfile/InnerClasses.java b/java/org/apache/tomcat/util/bcel/classfile/InnerClasses.java
index a01993c..d70b4d3 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/InnerClasses.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/InnerClasses.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -29,7 +28,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * to the source file of this class.
  * It is instantiated from the <em>Attribute.readAttribute()</em> method.
  *
- * @version $Id: InnerClasses.java 1181133 2011-10-10 18:49:14Z markt $
+ * @version $Id: InnerClasses.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Attribute
  */
@@ -74,22 +73,6 @@ public final class InnerClasses extends Attribute {
 
 
     /**
-     * Dump source file attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(number_of_classes);
-        for (int i = 0; i < number_of_classes; i++) {
-            inner_classes[i].dump(file);
-        }
-    }
-
-
-    /**
      * @param inner_classes the array of inner classes
      */
     public final void setInnerClasses( InnerClass[] inner_classes ) {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/LineNumberTable.java b/java/org/apache/tomcat/util/bcel/classfile/LineNumberTable.java
index 8c8ddd9..7db64d9 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/LineNumberTable.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/LineNumberTable.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -28,7 +27,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * purposes. This attribute is used by the <em>Code</em> attribute. It
  * contains pairs of PCs and line numbers.
  *
- * @version $Id: LineNumberTable.java 1181133 2011-10-10 18:49:14Z markt $
+ * @version $Id: LineNumberTable.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Code
  * @see LineNumber
@@ -73,22 +72,6 @@ public final class LineNumberTable extends Attribute {
 
 
     /**
-     * Dump line number table attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(line_number_table_length);
-        for (int i = 0; i < line_number_table_length; i++) {
-            line_number_table[i].dump(file);
-        }
-    }
-
-
-    /**
      * @param line_number_table the line number entries for this table
      */
     public final void setLineNumberTable( LineNumber[] line_number_table ) {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTable.java b/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTable.java
index 0b319c5..35d1545 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTable.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTable.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -27,7 +26,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * This class represents colection of local variables in a
  * method. This attribute is contained in the <em>Code</em> attribute.
  *
- * @version $Id: LocalVariableTable.java 1181133 2011-10-10 18:49:14Z markt $
+ * @version $Id: LocalVariableTable.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Code
  * @see LocalVariable
@@ -72,23 +71,7 @@ public class LocalVariableTable extends Attribute {
 
 
     /**
-     * Dump local variable table attribute to file stream in binary format.
      *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(local_variable_table_length);
-        for (int i = 0; i < local_variable_table_length; i++) {
-            local_variable_table[i].dump(file);
-        }
-    }
-
-
-    /** 
-     * 
      * @param index the variable slot
      * 
      * @return the first LocalVariable that matches the slot or null if not found
diff --git a/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTypeTable.java b/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTypeTable.java
index afa2133..2581b2f 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTypeTable.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTypeTable.java
@@ -17,7 +17,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -72,15 +71,6 @@ private int             local_variable_type_table_length; // Table of local
       local_variable_type_table[i] = new LocalVariable(dis, cpool);
   }
 
-  @Override
-  public final void dump(DataOutputStream file) throws IOException
-  {
-    super.dump(file);
-    file.writeShort(local_variable_type_table_length);
-    for(int i=0; i < local_variable_type_table_length; i++)
-      local_variable_type_table[i].dump(file);
-  }
-
   public final void setLocalVariableTable(LocalVariable[] local_variable_table)
   {
     this.local_variable_type_table = local_variable_table;
diff --git a/java/org/apache/tomcat/util/bcel/classfile/PMGClass.java b/java/org/apache/tomcat/util/bcel/classfile/PMGClass.java
index 9dfb892..8b5f78c 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/PMGClass.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/PMGClass.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -27,7 +26,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * This class is derived from <em>Attribute</em> and represents a reference
  * to a PMG attribute.
  *
- * @version $Id: PMGClass.java 1057670 2011-01-11 14:52:05Z markt $
+ * @version $Id: PMGClass.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Attribute
  */
@@ -67,20 +66,6 @@ public final class PMGClass extends Attribute {
 
 
     /**
-     * Dump source file attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(pmg_index);
-        file.writeShort(pmg_class_index);
-    }
-
-
-    /**
      * @return PMG name.
      */
     public final String getPMGName() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/RuntimeInvisibleAnnotations.java b/java/org/apache/tomcat/util/bcel/classfile/RuntimeInvisibleAnnotations.java
index e6959e9..3b53d75 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/RuntimeInvisibleAnnotations.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/RuntimeInvisibleAnnotations.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -62,11 +61,4 @@ public class RuntimeInvisibleAnnotations extends Annotations
         Annotations c = (Annotations) clone();
         return c;
     }
-
-    @Override
-    public final void dump(DataOutputStream dos) throws IOException
-    {
-        super.dump(dos);
-        writeAnnotations(dos);
-    }
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/RuntimeVisibleAnnotations.java b/java/org/apache/tomcat/util/bcel/classfile/RuntimeVisibleAnnotations.java
index 245cc9f..f9b8ab4 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/RuntimeVisibleAnnotations.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/RuntimeVisibleAnnotations.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -62,11 +61,4 @@ public class RuntimeVisibleAnnotations extends Annotations
         Annotations c = (Annotations) clone();
         return c;
     }
-
-    @Override
-    public final void dump(DataOutputStream dos) throws IOException
-    {
-        super.dump(dos);
-        writeAnnotations(dos);
-    }
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/Signature.java b/java/org/apache/tomcat/util/bcel/classfile/Signature.java
index 15ad6c2..453f2c9 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/Signature.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/Signature.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -27,7 +26,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * This class is derived from <em>Attribute</em> and represents a reference
  * to a GJ attribute.
  *
- * @version $Id: Signature.java 1057670 2011-01-11 14:52:05Z markt $
+ * @version $Id: Signature.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Attribute
  */
@@ -64,19 +63,6 @@ public final class Signature extends Attribute {
 
 
     /**
-     * Dump source file attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(signature_index);
-    }
-
-
-    /**
      * @return GJ signature.
      */
     public final String getSignature() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/SourceFile.java b/java/org/apache/tomcat/util/bcel/classfile/SourceFile.java
index f284a3e..4686868 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/SourceFile.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/SourceFile.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInput;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -29,7 +28,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * should appear per classfile.  The intention of this class is that it is
  * instantiated from the <em>Attribute.readAttribute()</em> method.
  *
- * @version $Id: SourceFile.java 1057670 2011-01-11 14:52:05Z markt $
+ * @version $Id: SourceFile.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Attribute
  */
@@ -73,19 +72,6 @@ public final class SourceFile extends Attribute {
 
 
     /**
-     * Dump source file attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(sourcefile_index);
-    }
-
-
-    /**
      * @return Source file name.
      */
     public final String getSourceFileName() {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/StackMap.java b/java/org/apache/tomcat/util/bcel/classfile/StackMap.java
index 963a6e1..7ae0b90 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/StackMap.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/StackMap.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -32,7 +31,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * within the Code attribute of a method. See CLDC specification
  * §5.3.1.2
  *
- * @version $Id: StackMap.java 1181133 2011-10-10 18:49:14Z markt $
+ * @version $Id: StackMap.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Code
  * @see     StackMapEntry
@@ -77,22 +76,6 @@ public final class StackMap extends Attribute {
 
 
     /**
-     * Dump line number table attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(map_length);
-        for (int i = 0; i < map_length; i++) {
-            map[i].dump(file);
-        }
-    }
-
-
-    /**
      * @param map Array of stack map entries
      */
     public final void setStackMap( StackMapEntry[] map ) {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/StackMapTable.java b/java/org/apache/tomcat/util/bcel/classfile/StackMapTable.java
index d1ebc9c..34b492e 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/StackMapTable.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/StackMapTable.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -32,7 +31,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * within the Code attribute of a method. See CLDC specification
  * §5.3.1.2
  *
- * @version $Id: StackMapTable.java 1181133 2011-10-10 18:49:14Z markt $
+ * @version $Id: StackMapTable.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Code
  * @see     StackMapEntry
@@ -77,22 +76,6 @@ public final class StackMapTable extends Attribute {
 
 
     /**
-     * Dump line number table attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        file.writeShort(map_length);
-        for (int i = 0; i < map_length; i++) {
-            map[i].dump(file);
-        }
-    }
-
-
-    /**
      * @param map Array of stack map entries
      */
     public final void setStackMapTable( StackMapTableEntry[] map ) {
diff --git a/java/org/apache/tomcat/util/bcel/classfile/Synthetic.java b/java/org/apache/tomcat/util/bcel/classfile/Synthetic.java
index 5c856a9..12919b3 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/Synthetic.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/Synthetic.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 
 import org.apache.tomcat.util.bcel.Constants;
@@ -32,7 +31,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * is intended to be instantiated from the
  * <em>Attribute.readAttribute()</em> method.
  *
- * @version $Id: Synthetic.java 1181133 2011-10-10 18:49:14Z markt $
+ * @version $Id: Synthetic.java 1377533 2012-08-26 22:22:59Z markt $
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
  * @see     Attribute
  */
@@ -76,21 +75,6 @@ public final class Synthetic extends Attribute {
 
 
     /**
-     * Dump source file attribute to file stream in binary format.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        if (length > 0) {
-            file.write(bytes, 0, length);
-        }
-    }
-
-
-    /**
      * @return String representation.
      */
     @Override
diff --git a/java/org/apache/tomcat/util/bcel/classfile/Unknown.java b/java/org/apache/tomcat/util/bcel/classfile/Unknown.java
index b570694..306b122 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/Unknown.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/Unknown.java
@@ -18,7 +18,6 @@
 package org.apache.tomcat.util.bcel.classfile;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
@@ -36,7 +35,7 @@ import org.apache.tomcat.util.bcel.Constants;
  * org.apache.tomcat.util.bcel.classfile.AttributeReader)">Attribute.addAttributeReader</a>.
 
  *
- * @version $Id: Unknown.java 1057670 2011-01-11 14:52:05Z markt $
+ * @version $Id: Unknown.java 1377533 2012-08-26 22:22:59Z markt $
  * @see org.apache.tomcat.util.bcel.classfile.Attribute
  * @see org.apache.tomcat.util.bcel.classfile.AttributeReader
  * @author  <A HREF="mailto:m.dahm at gmx.de">M. Dahm</A>
@@ -86,21 +85,6 @@ public final class Unknown extends Attribute {
 
 
     /**
-     * Dump unknown bytes to file stream.
-     *
-     * @param file Output file stream
-     * @throws IOException
-     */
-    @Override
-    public final void dump( DataOutputStream file ) throws IOException {
-        super.dump(file);
-        if (length > 0) {
-            file.write(bytes, 0, length);
-        }
-    }
-
-
-    /**
      * @return name of attribute.
      */
     @Override
diff --git a/java/org/apache/tomcat/util/buf/HexUtils.java b/java/org/apache/tomcat/util/buf/HexUtils.java
index b7ae7d9..c815866 100644
--- a/java/org/apache/tomcat/util/buf/HexUtils.java
+++ b/java/org/apache/tomcat/util/buf/HexUtils.java
@@ -34,22 +34,10 @@ public final class HexUtils {
      *  Table for HEX to DEC byte translation.
      */
     private static final int[] DEC = {
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
         00, 01, 02, 03, 04, 05, 06, 07,  8,  9, -1, -1, -1, -1, -1, -1,
         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, 10, 11, 12, 13, 14, 15,
     };
 
 
@@ -80,7 +68,12 @@ public final class HexUtils {
     }
 
     public static int getDec(int index){
-        return DEC[index];
+        // Fast for correct values, slower for incorrect ones
+        try {
+            return DEC[index - '0'];
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            return -1;
+        }
     }
 
     public static byte getHex(int index){
diff --git a/java/org/apache/tomcat/util/collections/ConcurrentCache.java b/java/org/apache/tomcat/util/collections/ConcurrentCache.java
new file mode 100644
index 0000000..3d882b6
--- /dev/null
+++ b/java/org/apache/tomcat/util/collections/ConcurrentCache.java
@@ -0,0 +1,59 @@
+/*
+ * 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.tomcat.util.collections;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+public final class ConcurrentCache<K,V> {
+
+    private final int size;
+
+    private final Map<K,V> eden;
+
+    private final Map<K,V> longterm;
+
+    public ConcurrentCache(int size) {
+        this.size = size;
+        this.eden = new ConcurrentHashMap<K,V>(size);
+        this.longterm = new WeakHashMap<K,V>(size);
+    }
+
+    public V get(K k) {
+        V v = this.eden.get(k);
+        if (v == null) {
+            synchronized (longterm) {
+                v = this.longterm.get(k);
+            }
+            if (v != null) {
+                this.eden.put(k, v);
+            }
+        }
+        return v;
+    }
+
+    public void put(K k, V v) {
+        if (this.eden.size() >= size) {
+            synchronized (longterm) {
+                this.longterm.putAll(this.eden);
+            }
+            this.eden.clear();
+        }
+        this.eden.put(k, v);
+    }
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItem.java b/java/org/apache/tomcat/util/http/fileupload/FileItem.java
index bb69226..748d90b 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileItem.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileItem.java
@@ -30,7 +30,7 @@ import java.io.UnsupportedEncodingException;
  * <p> After retrieving an instance of this class from a {@link
  * org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} instance (see
  * {@link org.apache.tomcat.util.http.fileupload.FileUpload
- * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may
+ * #parseRequest(RequestContext)}), you may
  * either request all contents of the file at once using {@link #get()} or
  * request an {@link java.io.InputStream InputStream} with
  * {@link #getInputStream()} and process the file without attempting to load
@@ -48,7 +48,7 @@ import java.io.UnsupportedEncodingException;
  * @author <a href="mailto:jvanzyl at apache.org">Jason van Zyl</a>
  * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
  *
- * @version $Id: FileItem.java 981816 2010-08-03 10:44:58Z markt $
+ * @version $Id: FileItem.java 1373051 2012-08-14 19:47:38Z markt $
  */
 public interface FileItem extends Serializable {
 
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java b/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java
index 2e710ce..f19a690 100644
--- a/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java
+++ b/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java
@@ -83,7 +83,7 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
      * @param value value of this header
      */
     public synchronized void addHeader(String name, String value) {
-        String nameLower = name.toLowerCase();
+        String nameLower = name.toLowerCase(Locale.ENGLISH);
         List<String> headerValueList = headerNameToValueListMap.get(nameLower);
         if (null == headerValueList) {
             headerValueList = new ArrayList<String>();
diff --git a/java/org/apache/tomcat/util/http/parser/AstAttribute.java b/java/org/apache/tomcat/util/http/parser/AstAttribute.java
deleted file mode 100644
index 105c09f..0000000
--- a/java/org/apache/tomcat/util/http/parser/AstAttribute.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  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.tomcat.util.http.parser;
-
-/**
- * Represents an attribute as per section 3.6 of RFC 2616. Originally generated
- * by <a href="http://javacc.java.net/doc/JJTree.html"> JJTree</a>.
- */
-public class AstAttribute extends SimpleNode {
-    public AstAttribute(int id) {
-        super(id);
-    }
-
-    public AstAttribute(HttpParser p, int id) {
-        super(p, id);
-    }
-
-    @Override
-    public String toString() {
-        return value.toString();
-    }
-}
diff --git a/java/org/apache/tomcat/util/http/parser/AstMediaType.java b/java/org/apache/tomcat/util/http/parser/AstMediaType.java
deleted file mode 100644
index 758d10e..0000000
--- a/java/org/apache/tomcat/util/http/parser/AstMediaType.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- *  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.tomcat.util.http.parser;
-
-/**
- * Represents a media-type as per section 3.7 of RFC 2616. Originally generated
- * by <a href="http://javacc.java.net/doc/JJTree.html"> JJTree</a>.
- */
-public class AstMediaType extends SimpleNode {
-
-    private static final String CHARSET = "charset";
-
-    public AstMediaType(int id) {
-        super(id);
-    }
-
-    public AstMediaType(HttpParser p, int id) {
-        super(p, id);
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append(children[0].toString());
-        sb.append('/');
-        sb.append(children[1].toString());
-        for (int i = 2; i < children.length; i++) {
-            String s = children[i].toString();
-            // Invalid parameters will have zero length - skip them
-            if (s.length() > 0) {
-                sb.append(';');
-                sb.append(s);
-            }
-        }
-        return sb.toString();
-    }
-
-    public String toStringNoCharset() {
-        StringBuilder sb = new StringBuilder();
-        sb.append(children[0].toString());
-        sb.append('/');
-        sb.append(children[1].toString());
-        for (int i = 2; i < children.length; i++) {
-            AstParameter p = (AstParameter) children[i];
-            if (!CHARSET.equalsIgnoreCase(
-                    p.children[0].jjtGetValue().toString())) {
-                String s = p.toString();
-                // Invalid parameters will have zero length - skip them
-                if (s.length() > 0) {
-                    sb.append(';');
-                    sb.append(p.toString());
-                }
-            }
-        }
-        return sb.toString();
-    }
-
-    public String getCharset() {
-        for (int i = 2; i < children.length; i++) {
-            AstParameter p = (AstParameter) children[i];
-            if (CHARSET.equalsIgnoreCase(
-                    p.children[0].jjtGetValue().toString())) {
-                return p.children[1].jjtGetValue().toString();
-            }
-        }
-        return null;
-    }
-}
diff --git a/java/org/apache/tomcat/util/http/parser/AstParameter.java b/java/org/apache/tomcat/util/http/parser/AstParameter.java
deleted file mode 100644
index 52d2c6e..0000000
--- a/java/org/apache/tomcat/util/http/parser/AstParameter.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *  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.tomcat.util.http.parser;
-
-/**
- * Represents a parameter as per section 3.6 of RFC 2616. Originally generated
- * by <a href="http://javacc.java.net/doc/JJTree.html"> JJTree</a>.
- */
-public class AstParameter extends SimpleNode {
-    public AstParameter(int id) {
-        super(id);
-    }
-
-    public AstParameter(HttpParser p, int id) {
-        super(p, id);
-    }
-
-    @Override
-    public String toString() {
-        if (children.length != 2) {
-            // Invalid input - swallow it.
-            return "";
-        }
-        StringBuilder sb = new StringBuilder();
-        sb.append(children[0].toString());
-        sb.append("=");
-        sb.append(children[1].toString());
-        return sb.toString();
-    }
-}
diff --git a/java/org/apache/tomcat/util/http/parser/AstSubType.java b/java/org/apache/tomcat/util/http/parser/AstSubType.java
deleted file mode 100644
index b1b6dec..0000000
--- a/java/org/apache/tomcat/util/http/parser/AstSubType.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  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.tomcat.util.http.parser;
-
-/**
- * Represents a sub-type as per section 3.7 of RFC 2616. Originally generated by
- * <a href="http://javacc.java.net/doc/JJTree.html"> JJTree</a>.
- */
-public class AstSubType extends SimpleNode {
-    public AstSubType(int id) {
-        super(id);
-    }
-
-    public AstSubType(HttpParser p, int id) {
-        super(p, id);
-    }
-
-    @Override
-    public String toString() {
-        return value.toString();
-    }
-}
diff --git a/java/org/apache/tomcat/util/http/parser/AstType.java b/java/org/apache/tomcat/util/http/parser/AstType.java
deleted file mode 100644
index 97d36d8..0000000
--- a/java/org/apache/tomcat/util/http/parser/AstType.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  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.tomcat.util.http.parser;
-
-/**
- * Represents a type as per section 3.7 of RFC 2616. Originally generated by <a
- * href="http://javacc.java.net/doc/JJTree.html"> JJTree</a>.
- */
-public class AstType extends SimpleNode {
-    public AstType(int id) {
-        super(id);
-    }
-
-    public AstType(HttpParser p, int id) {
-        super(p, id);
-    }
-
-    @Override
-    public String toString() {
-        return value.toString();
-    }
-}
diff --git a/java/org/apache/tomcat/util/http/parser/AstValue.java b/java/org/apache/tomcat/util/http/parser/AstValue.java
deleted file mode 100644
index 7dd91e1..0000000
--- a/java/org/apache/tomcat/util/http/parser/AstValue.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  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.tomcat.util.http.parser;
-
-/**
- * Represents a value as per section 3.6 of RFC 2616. Originally generated by <a
- * href="http://javacc.java.net/doc/JJTree.html"> JJTree</a>.
- */
-public class AstValue extends SimpleNode {
-    @Override
-    public Object jjtGetValue() {
-        String s = value.toString();
-        if (s.charAt(0) == '\"') {
-            // Quoted
-            return s.substring(1, s.length() - 1).replaceAll("\\\"", "\"");
-        } else {
-            // Unquoted
-            return s;
-        }
-    }
-
-    public AstValue(int id) {
-        super(id);
-    }
-
-    public AstValue(HttpParser p, int id) {
-        super(p, id);
-    }
-
-    @Override
-    public String toString() {
-        return value.toString();
-    }
-}
diff --git a/java/org/apache/tomcat/util/http/parser/HttpParser.java b/java/org/apache/tomcat/util/http/parser/HttpParser.java
index 15d28f2..2117d31 100644
--- a/java/org/apache/tomcat/util/http/parser/HttpParser.java
+++ b/java/org/apache/tomcat/util/http/parser/HttpParser.java
@@ -1,348 +1,400 @@
-/* Generated By:JJTree&JavaCC: Do not edit this line. HttpParser.java */
+/*
+ * 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.tomcat.util.http.parser;
- at SuppressWarnings("all") // Ignore warnings in generated code
-public class HttpParser/*@bgen(jjtree)*/implements HttpParserTreeConstants, HttpParserConstants {/*@bgen(jjtree)*/
-  protected JJTHttpParserState jjtree = new JJTHttpParserState();
 
-/*
- * Content-Type
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * HTTP header value parser implementation. Parsing HTTP headers as per RFC2616
+ * is not always as simple as it first appears. For headers that only use tokens
+ * the simple approach will normally be sufficient. However, for the other
+ * headers, while simple code meets 99.9% of cases, there are often some edge
+ * cases that make things far more complicated.
+ *
+ * The purpose of this parser is to let the parser worry about the edge cases.
+ * It provides tolerant (where safe to do so) parsing of HTTP header values
+ * assuming that wrapped header lines have already been unwrapped. (The Tomcat
+ * header processing code does the unwrapping.)
+ *
+ * Provides parsing of the following HTTP header values as per RFC 2616:
+ * - Authorization for DIGEST authentication
+ * - MediaType (used for Content-Type header)
+ *
+ * Support for additional headers will be provided as required.
  */
-  final public AstMediaType MediaType() throws ParseException {
-                                       /*@bgen(jjtree) MediaType */
-  AstMediaType jjtn000 = new AstMediaType(JJTMEDIATYPE);
-  boolean jjtc000 = true;
-  jjtree.openNodeScope(jjtn000);
-    try {
-      Type();
-      jj_consume_token(FORWARD_SLASH);
-      SubType();
-      label_1:
-      while (true) {
-        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-        case SEMI_COLON:
-          ;
-          break;
-        default:
-          jj_la1[0] = jj_gen;
-          break label_1;
+public class HttpParser {
+
+    private static final Integer FIELD_TYPE_TOKEN = Integer.valueOf(0);
+    private static final Integer FIELD_TYPE_QUOTED_STRING = Integer.valueOf(1);
+    private static final Integer FIELD_TYPE_TOKEN_OR_QUOTED_STRING = Integer.valueOf(2);
+    private static final Integer FIELD_TYPE_LHEX = Integer.valueOf(3);
+    private static final Integer FIELD_TYPE_QUOTED_LHEX = Integer.valueOf(4);
+
+    private static final Map<String,Integer> fieldTypes =
+            new HashMap<String,Integer>();
+
+    private static final boolean isToken[] = new boolean[128];
+    private static final boolean isHex[] = new boolean[128];
+
+    static {
+        // Digest field types
+        fieldTypes.put("username", FIELD_TYPE_QUOTED_STRING);
+        fieldTypes.put("realm", FIELD_TYPE_QUOTED_STRING);
+        fieldTypes.put("nonce", FIELD_TYPE_QUOTED_STRING);
+        fieldTypes.put("digest-uri", FIELD_TYPE_QUOTED_STRING);
+        fieldTypes.put("response", FIELD_TYPE_QUOTED_LHEX);
+        fieldTypes.put("algorithm", FIELD_TYPE_TOKEN);
+        fieldTypes.put("cnonce", FIELD_TYPE_QUOTED_STRING);
+        fieldTypes.put("opaque", FIELD_TYPE_QUOTED_STRING);
+        fieldTypes.put("qop", FIELD_TYPE_TOKEN);
+        fieldTypes.put("nc", FIELD_TYPE_LHEX);
+
+        // Setup the flag arrays
+        for (int i = 0; i < 128; i++) {
+            if (i < 32) {
+                isToken[i] = false;
+            } else if (i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
+                       i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
+                       i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
+                       i == '{' || i == '}' || i == ' ' || i == '\t') {
+                isToken[i] = false;
+            } else {
+                isToken[i] = true;
+            }
+
+            if (i >= '0' && i <= '9' || i >= 'A' && i <= 'F' ||
+                    i >= 'a' && i <= 'f') {
+                isHex[i] = true;
+            } else {
+                isHex[i] = false;
+            }
         }
-        jj_consume_token(SEMI_COLON);
-        Parameter();
-      }
-      jj_consume_token(0);
-                                                                          jjtree.closeNodeScope(jjtn000, true);
-                                                                          jjtc000 = false;
-        {if (true) return jjtn000;}
-    } catch (Throwable jjte000) {
-      if (jjtc000) {
-        jjtree.clearNodeScope(jjtn000);
-        jjtc000 = false;
-      } else {
-        jjtree.popNode();
-      }
-      if (jjte000 instanceof RuntimeException) {
-        {if (true) throw (RuntimeException)jjte000;}
-      }
-      if (jjte000 instanceof ParseException) {
-        {if (true) throw (ParseException)jjte000;}
-      }
-      {if (true) throw (Error)jjte000;}
-    } finally {
-      if (jjtc000) {
-        jjtree.closeNodeScope(jjtn000, true);
-      }
     }
-    throw new Error("Missing return statement in function");
-  }
-
-  final public void Type() throws ParseException {
-                     /*@bgen(jjtree) Type */
-                      AstType jjtn000 = new AstType(JJTTYPE);
-                      boolean jjtc000 = true;
-                      jjtree.openNodeScope(jjtn000);Token t = null;
-    try {
-      t = jj_consume_token(HTTP_TOKEN);
-                     jjtree.closeNodeScope(jjtn000, true);
-                     jjtc000 = false;
-                     jjtn000.jjtSetValue(t.image.trim());
-    } finally {
-      if (jjtc000) {
-        jjtree.closeNodeScope(jjtn000, true);
-      }
-    }
-  }
-
-  final public void SubType() throws ParseException {
-                          /*@bgen(jjtree) SubType */
-                           AstSubType jjtn000 = new AstSubType(JJTSUBTYPE);
-                           boolean jjtc000 = true;
-                           jjtree.openNodeScope(jjtn000);Token t = null;
-    try {
-      t = jj_consume_token(HTTP_TOKEN);
-                     jjtree.closeNodeScope(jjtn000, true);
-                     jjtc000 = false;
-                     jjtn000.jjtSetValue(t.image.trim());
-    } finally {
-      if (jjtc000) {
-        jjtree.closeNodeScope(jjtn000, true);
-      }
-    }
-  }
-
-  final public void Parameter() throws ParseException {
-                               /*@bgen(jjtree) Parameter */
-  AstParameter jjtn000 = new AstParameter(JJTPARAMETER);
-  boolean jjtc000 = true;
-  jjtree.openNodeScope(jjtn000);
-    try {
-      Attribute();
-      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-      case EQUALS:
-        jj_consume_token(EQUALS);
-        Value();
-        break;
-      default:
-        jj_la1[1] = jj_gen;
-        ;
-      }
-    } catch (Throwable jjte000) {
-      if (jjtc000) {
-        jjtree.clearNodeScope(jjtn000);
-        jjtc000 = false;
-      } else {
-        jjtree.popNode();
-      }
-      if (jjte000 instanceof RuntimeException) {
-        {if (true) throw (RuntimeException)jjte000;}
-      }
-      if (jjte000 instanceof ParseException) {
-        {if (true) throw (ParseException)jjte000;}
-      }
-      {if (true) throw (Error)jjte000;}
-    } finally {
-      if (jjtc000) {
-        jjtree.closeNodeScope(jjtn000, true);
-      }
-    }
-  }
-
-  final public void Attribute() throws ParseException {
-                                /*@bgen(jjtree) Attribute */
-                                 AstAttribute jjtn000 = new AstAttribute(JJTATTRIBUTE);
-                                 boolean jjtc000 = true;
-                                 jjtree.openNodeScope(jjtn000);Token t = null;
-    try {
-      t = jj_consume_token(HTTP_TOKEN);
-                     jjtree.closeNodeScope(jjtn000, true);
-                     jjtc000 = false;
-                     jjtn000.jjtSetValue(t.image.trim());
-    } finally {
-      if (jjtc000) {
-        jjtree.closeNodeScope(jjtn000, true);
-      }
+
+    /**
+     * Parses an HTTP Authorization header for DIGEST authentication as per RFC
+     * 2617 section 3.2.2.
+     *
+     * @param input The header value to parse
+     *
+     * @return  A map of directives and values as {@link String}s or
+     *          <code>null</code> if a parsing error occurs. Although the
+     *          values returned are {@link String}s they will have been
+     *          validated to ensure that they conform to RFC 2617.
+     *
+     * @throws IllegalArgumentException If the header does not conform to RFC
+     *                                  2617
+     * @throws IOException If an error occurs while reading the input
+     */
+    public static Map<String,String> parseAuthorizationDigest (
+            StringReader input) throws IllegalArgumentException, IOException {
+
+        Map<String,String> result = new HashMap<String,String>();
+
+        if (skipConstant(input, "Digest") != SkipConstantResult.FOUND) {
+            return null;
+        }
+        // All field names are valid tokens
+        String field = readToken(input);
+        if (field == null) {
+            return null;
+        }
+        while (!field.equals("")) {
+            if (skipConstant(input, "=") != SkipConstantResult.FOUND) {
+                return null;
+            }
+            String value = null;
+            Integer type = fieldTypes.get(field.toLowerCase(Locale.US));
+            if (type == null) {
+                // auth-param = token "=" ( token | quoted-string )
+                type = FIELD_TYPE_TOKEN_OR_QUOTED_STRING;
+            }
+            switch (type.intValue()) {
+                case 0:
+                    // FIELD_TYPE_TOKEN
+                    value = readToken(input);
+                    break;
+                case 1:
+                    // FIELD_TYPE_QUOTED_STRING
+                    value = readQuotedString(input, false);
+                    break;
+                case 2:
+                    // FIELD_TYPE_TOKEN_OR_QUOTED_STRING
+                    value = readTokenOrQuotedString(input, false);
+                    break;
+                case 3:
+                    // FIELD_TYPE_LHEX
+                    value = readLhex(input);
+                    break;
+                case 4:
+                    // FIELD_TYPE_QUOTED_LHEX
+                    value = readQuotedLhex(input);
+                    break;
+                default:
+                    // Error
+                    throw new IllegalArgumentException(
+                            "TODO i18n: Unsupported type");
+            }
+
+            if (value == null) {
+                return null;
+            }
+            result.put(field, value);
+
+            if (skipConstant(input, ",") == SkipConstantResult.NOT_FOUND) {
+                return null;
+            }
+            field = readToken(input);
+            if (field == null) {
+                return null;
+            }
+        }
+
+        return result;
     }
-  }
-
-  final public void Value() throws ParseException {
-                       /*@bgen(jjtree) Value */
-                        AstValue jjtn000 = new AstValue(JJTVALUE);
-                        boolean jjtc000 = true;
-                        jjtree.openNodeScope(jjtn000);Token t = null;
-    try {
-      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-      case HTTP_TOKEN:
-        t = jj_consume_token(HTTP_TOKEN);
-                     jjtree.closeNodeScope(jjtn000, true);
-                     jjtc000 = false;
-                     jjtn000.jjtSetValue(t.image.trim());
-        break;
-      case QUOTED_STRING:
-        t = jj_consume_token(QUOTED_STRING);
-                                                                                  jjtree.closeNodeScope(jjtn000, true);
-                                                                                  jjtc000 = false;
-                                                                                  jjtn000.jjtSetValue(t.image.trim());
-        break;
-      default:
-        jj_la1[2] = jj_gen;
-        jj_consume_token(-1);
-        throw new ParseException();
-      }
-    } finally {
-      if (jjtc000) {
-        jjtree.closeNodeScope(jjtn000, true);
-      }
+
+    public static MediaType parseMediaType(StringReader input)
+            throws IOException {
+
+        // Type (required)
+        String type = readToken(input);
+        if (type == null || type.length() == 0) {
+            return null;
+        }
+
+        if (skipConstant(input, "/") == SkipConstantResult.NOT_FOUND) {
+            return null;
+        }
+
+        // Subtype (required)
+        String subtype = readToken(input);
+        if (subtype == null || subtype.length() == 0) {
+            return null;
+        }
+
+        LinkedHashMap<String,String> parameters =
+                new LinkedHashMap<String,String>();
+
+        SkipConstantResult lookForSemiColon = skipConstant(input, ";");
+        if (lookForSemiColon == SkipConstantResult.NOT_FOUND) {
+            return null;
+        }
+        while (lookForSemiColon == SkipConstantResult.FOUND) {
+            String attribute = readToken(input);
+
+            if (skipConstant(input, "=") == SkipConstantResult.FOUND) {
+                String value = readTokenOrQuotedString(input, true);
+                parameters.put(attribute.toLowerCase(Locale.US), value);
+            } else {
+                parameters.put(attribute.toLowerCase(Locale.US), "");
+            }
+
+            lookForSemiColon = skipConstant(input, ";");
+            if (lookForSemiColon == SkipConstantResult.NOT_FOUND) {
+                return null;
+            }
+        }
+
+        return new MediaType(type, subtype, parameters);
     }
-  }
-
-  /** Generated Token Manager. */
-  public HttpParserTokenManager token_source;
-  SimpleCharStream jj_input_stream;
-  /** Current token. */
-  public Token token;
-  /** Next token. */
-  public Token jj_nt;
-  private int jj_ntk;
-  private int jj_gen;
-  final private int[] jj_la1 = new int[3];
-  static private int[] jj_la1_0;
-  static {
-      jj_la1_init_0();
-   }
-   private static void jj_la1_init_0() {
-      jj_la1_0 = new int[] {0x2,0x4,0x180,};
-   }
-
-  /** Constructor with InputStream. */
-  public HttpParser(java.io.InputStream stream) {
-     this(stream, null);
-  }
-  /** Constructor with InputStream and supplied encoding */
-  public HttpParser(java.io.InputStream stream, String encoding) {
-    try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
-    token_source = new HttpParserTokenManager(jj_input_stream);
-    token = new Token();
-    jj_ntk = -1;
-    jj_gen = 0;
-    for (int i = 0; i < 3; i++) jj_la1[i] = -1;
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.InputStream stream) {
-     ReInit(stream, null);
-  }
-  /** Reinitialise. */
-  public void ReInit(java.io.InputStream stream, String encoding) {
-    try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
-    token_source.ReInit(jj_input_stream);
-    token = new Token();
-    jj_ntk = -1;
-    jjtree.reset();
-    jj_gen = 0;
-    for (int i = 0; i < 3; i++) jj_la1[i] = -1;
-  }
-
-  /** Constructor. */
-  public HttpParser(java.io.Reader stream) {
-    jj_input_stream = new SimpleCharStream(stream, 1, 1);
-    token_source = new HttpParserTokenManager(jj_input_stream);
-    token = new Token();
-    jj_ntk = -1;
-    jj_gen = 0;
-    for (int i = 0; i < 3; i++) jj_la1[i] = -1;
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.Reader stream) {
-    jj_input_stream.ReInit(stream, 1, 1);
-    token_source.ReInit(jj_input_stream);
-    token = new Token();
-    jj_ntk = -1;
-    jjtree.reset();
-    jj_gen = 0;
-    for (int i = 0; i < 3; i++) jj_la1[i] = -1;
-  }
-
-  /** Constructor with generated Token Manager. */
-  public HttpParser(HttpParserTokenManager tm) {
-    token_source = tm;
-    token = new Token();
-    jj_ntk = -1;
-    jj_gen = 0;
-    for (int i = 0; i < 3; i++) jj_la1[i] = -1;
-  }
-
-  /** Reinitialise. */
-  public void ReInit(HttpParserTokenManager tm) {
-    token_source = tm;
-    token = new Token();
-    jj_ntk = -1;
-    jjtree.reset();
-    jj_gen = 0;
-    for (int i = 0; i < 3; i++) jj_la1[i] = -1;
-  }
-
-  private Token jj_consume_token(int kind) throws ParseException {
-    Token oldToken;
-    if ((oldToken = token).next != null) token = token.next;
-    else token = token.next = token_source.getNextToken();
-    jj_ntk = -1;
-    if (token.kind == kind) {
-      jj_gen++;
-      return token;
+
+    public static String unquote(String input) {
+        if (input == null || input.length() < 2 || input.charAt(0) != '"') {
+            return input;
+        }
+
+        StringBuilder result = new StringBuilder();
+        for (int i = 1 ; i < (input.length() - 1); i++) {
+            char c = input.charAt(i);
+            if (input.charAt(i) == '\\') {
+                i++;
+                result.append(input.charAt(i));
+            } else {
+                result.append(c);
+            }
+        }
+        return result.toString();
     }
-    token = oldToken;
-    jj_kind = kind;
-    throw generateParseException();
-  }
-
-
-/** Get the next Token. */
-  final public Token getNextToken() {
-    if (token.next != null) token = token.next;
-    else token = token.next = token_source.getNextToken();
-    jj_ntk = -1;
-    jj_gen++;
-    return token;
-  }
-
-/** Get the specific Token. */
-  final public Token getToken(int index) {
-    Token t = token;
-    for (int i = 0; i < index; i++) {
-      if (t.next != null) t = t.next;
-      else t = t.next = token_source.getNextToken();
+
+    private static SkipConstantResult skipConstant(StringReader input,
+            String constant) throws IOException {
+        int len = constant.length();
+
+        int c = input.read();
+        while (c == 32 || c == 9) {
+            c = input.read();
+        }
+
+        for (int i = 0; i < len; i++) {
+            if (i == 0 && c == -1) {
+                return SkipConstantResult.EOF;
+            }
+            if (c != constant.charAt(i)) {
+                input.skip(-(i + 1));
+                return SkipConstantResult.NOT_FOUND;
+            }
+            if (i != (len - 1)) {
+                c = input.read();
+            }
+        }
+        return SkipConstantResult.FOUND;
     }
-    return t;
-  }
-
-  private int jj_ntk() {
-    if ((jj_nt=token.next) == null)
-      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
-    else
-      return (jj_ntk = jj_nt.kind);
-  }
-
-  private java.util.List<int[]> jj_expentries = new java.util.ArrayList<int[]>();
-  private int[] jj_expentry;
-  private int jj_kind = -1;
-
-  /** Generate ParseException. */
-  public ParseException generateParseException() {
-    jj_expentries.clear();
-    boolean[] la1tokens = new boolean[15];
-    if (jj_kind >= 0) {
-      la1tokens[jj_kind] = true;
-      jj_kind = -1;
+
+    /**
+     * @return  the token if one was found, the empty string if no data was
+     *          available to read or <code>null</code> if data other than a
+     *          token was found
+     */
+    private static String readToken(StringReader input) throws IOException {
+        StringBuilder result = new StringBuilder();
+
+        int c = input.read();
+
+        // Skip lws
+        while (c == 32 || c == 9) {
+            c = input.read();
+        }
+
+        while (c != -1 && isToken[c]) {
+            result.append((char) c);
+            c = input.read();
+        }
+        // Skip back so non-token character is available for next read
+        input.skip(-1);
+
+        if (c != -1 && result.length() == 0) {
+            return null;
+        } else {
+            return result.toString();
+        }
     }
-    for (int i = 0; i < 3; i++) {
-      if (jj_la1[i] == jj_gen) {
-        for (int j = 0; j < 32; j++) {
-          if ((jj_la1_0[i] & (1<<j)) != 0) {
-            la1tokens[j] = true;
-          }
+
+    /**
+     * @return the quoted string if one was found, null if data other than a
+     *         quoted string was found or null if the end of data was reached
+     *         before the quoted string was terminated
+     */
+    private static String readQuotedString(StringReader input,
+            boolean returnQuoted) throws IOException {
+
+        int c = input.read();
+
+        // Skip lws
+        while (c == 32 || c == 9) {
+            c = input.read();
+        }
+
+        if (c != '"') {
+            return null;
+        }
+
+        StringBuilder result = new StringBuilder();
+        if (returnQuoted) {
+            result.append('\"');
         }
-      }
+        c = input.read();
+
+        while (c != '"') {
+            if (c == -1) {
+                return null;
+            } else if (c == '\\') {
+                c = input.read();
+                if (returnQuoted) {
+                    result.append('\\');
+                }
+                result.append(c);
+            } else {
+                result.append((char) c);
+            }
+            c = input.read();
+        }
+        if (returnQuoted) {
+            result.append('\"');
+        }
+
+        return result.toString();
     }
-    for (int i = 0; i < 15; i++) {
-      if (la1tokens[i]) {
-        jj_expentry = new int[1];
-        jj_expentry[0] = i;
-        jj_expentries.add(jj_expentry);
-      }
+
+    private static String readTokenOrQuotedString(StringReader input,
+            boolean returnQuoted) throws IOException {
+        input.mark(1);
+        int c = input.read();
+        input.reset();
+
+        if (c == '"') {
+            return readQuotedString(input, returnQuoted);
+        } else {
+            return readToken(input);
+        }
     }
-    int[][] exptokseq = new int[jj_expentries.size()][];
-    for (int i = 0; i < jj_expentries.size(); i++) {
-      exptokseq[i] = jj_expentries.get(i);
+
+    /**
+     * Parses lower case hex but permits upper case hex to be used (converting
+     * it to lower case before returning).
+     *
+     * @return the lower case hex if present or <code>null</code> if data other
+     *         than lower case hex was found
+     */
+    private static String readLhex(StringReader input) throws IOException {
+        StringBuilder result = new StringBuilder();
+
+        int c = input.read();
+
+        // Skip lws
+        while (c == 32 || c == 9) {
+            c = input.read();
+        }
+
+        while (c != -1 && isHex[c]) {
+            result.append((char) c);
+            c = input.read();
+        }
+        // Skip back so non-hex character is available for next read
+        input.skip(-1);
+
+        if (result.length() == 0) {
+            return null;
+        } else {
+            return result.toString().toLowerCase(Locale.US);
+        }
     }
-    return new ParseException(token, exptokseq, tokenImage);
-  }
 
-  /** Enable tracing. */
-  final public void enable_tracing() {
-  }
+    private static String readQuotedLhex(StringReader input)
+            throws IOException {
 
-  /** Disable tracing. */
-  final public void disable_tracing() {
-  }
+        if (skipConstant(input, "\"") != SkipConstantResult.FOUND) {
+            return null;
+        }
+        String result = readLhex(input);
+        if (skipConstant(input, "\"") == SkipConstantResult.NOT_FOUND) {
+            return null;
+        }
 
+        return result;
+    }
+
+    private static enum SkipConstantResult {
+        FOUND,
+        NOT_FOUND,
+        EOF
+    }
 }
diff --git a/java/org/apache/tomcat/util/http/parser/HttpParser.jjt b/java/org/apache/tomcat/util/http/parser/HttpParser.jjt
deleted file mode 100644
index 957155d..0000000
--- a/java/org/apache/tomcat/util/http/parser/HttpParser.jjt
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Parsing HTTP headers as per RFC2616 is not always as simple as it first
- * appears. For headers that only use tokens the simple approach will normally
- * be sufficient. However, for the other headers, while simple code meets 99.9%
- * of cases, there are often some edge cases that make things far more
- * complicated.
- *
- * The purpose of this parser is to let the parser worry about the edge cases.
- * It provides strict parsing of HTTP header values assuming that wrapped header
- * lines have already been unwrapped. (The Tomcat header processing code does
- * the unwrapping.)
- *
- * Provides parsing of the following HTTP header values as per RFC 2616:
- * - Content-Type
- *     Note: The parser tolerates invalid parameters that do not include a
- *           value. These parameters are available in the Parser node collection
- *           but will be skipped by the various toString() methods. See BZ 53353
- *           for an example.
- *
- * Support for additional headers will be provided as required.
- */
-
-/* Option Declaration */
-options
-{
-    STATIC=false;
-    NODE_PREFIX="Ast";
-    MULTI=true;
-    NODE_DEFAULT_VOID=true;
-    JAVA_UNICODE_ESCAPE=false;
-    UNICODE_INPUT=true;
-    BUILD_NODE_FILES=true;
-}
-
-
-/* Parser Declaration */
-PARSER_BEGIN( HttpParser )
-package org.apache.tomcat.util.http.parser;
-public class HttpParser
-{
-}
-PARSER_END( HttpParser )
-
-
-/*
- * Content-Type
- */
-AstMediaType MediaType() #MediaType : {}
-{
-    Type() <FORWARD_SLASH> SubType() ( <SEMI_COLON> Parameter())* <EOF> {
-        return jjtThis;
-    }
-}
-
-void Type() #Type : { Token t = null; }
-{
-    t=<HTTP_TOKEN> { jjtThis.jjtSetValue(t.image.trim()); }
-}
-
-void SubType() #SubType :{ Token t = null; }
-{
-    t=<HTTP_TOKEN> { jjtThis.jjtSetValue(t.image.trim()); }
-}
-
-void Parameter() #Parameter : {}
-{
-    Attribute() (<EQUALS> Value())?
-}
-
-void Attribute() # Attribute : { Token t = null; }
-{
-    t=<HTTP_TOKEN> { jjtThis.jjtSetValue(t.image.trim()); }
-}
-
-void Value() #Value : { Token t = null; }
-{
-    t=<HTTP_TOKEN> { jjtThis.jjtSetValue(t.image.trim()); } | t=<QUOTED_STRING> { jjtThis.jjtSetValue(t.image.trim()); }
-}
-
-
-<DEFAULT> TOKEN:
-{
-  < SEMI_COLON :    ";" >
-| < EQUALS :        "=" >
-| < FORWARD_SLASH : "/" >
-| < SP :            " " >
-| < HT :            "\t" >
-| < LWS :           (<HT> | <SP>)+ >
-| < HTTP_TOKEN :    (<LWS>)? (<HTTP_TOKEN_CHAR>)+ (<LWS>)? >
-| < QUOTED_STRING : (<LWS>)? <START_QUOTE> <QUOTED_TEXT> <END_QUOTE> (<LWS>)? >
-| < START_QUOTE :   "\"" > : IN_QUOTED_TEXT
-| < #HTTP_TOKEN_CHAR:
-     [
-     "\u0021",
-     "\u0023"-"\u0027",
-     "\u002a"-"\u002b",
-     "\u002d"-"\u002e",
-     "\u0030"-"\u0039",
-     "\u0041"-"\u005a",
-     "\u005e"-"\u007a",
-     "\u007c",
-     "\u007e"
-     ]
-  >
-}
-
-<IN_QUOTED_TEXT> TOKEN :
-{
-  < #QUOTED_TEXT :   (<QUOTED_TEXT_CHAR> | ("\\" <CHAR> ))* >
-| < #END_QUOTE :     "\"" >
-| < #QUOTED_TEXT_CHAR:
-     [
-     "\u0009",
-     "\u0020"-"\u0021",
-     "\u0023"-"\u005b",
-     "\u005d"-"\u00ff"
-     ]
-  >
-| < #CHAR:
-     [
-     "\u0000"-"\u007f"
-     ]
-  >
-}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/http/parser/HttpParserConstants.java b/java/org/apache/tomcat/util/http/parser/HttpParserConstants.java
deleted file mode 100644
index 74379e1..0000000
--- a/java/org/apache/tomcat/util/http/parser/HttpParserConstants.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Generated By:JJTree&JavaCC: Do not edit this line. HttpParserConstants.java */
-package org.apache.tomcat.util.http.parser;
-
-
-/**
- * Token literal values and constants.
- * Generated by org.javacc.parser.OtherFilesGen#start()
- */
-public interface HttpParserConstants {
-
-  /** End of File. */
-  int EOF = 0;
-  /** RegularExpression Id. */
-  int SEMI_COLON = 1;
-  /** RegularExpression Id. */
-  int EQUALS = 2;
-  /** RegularExpression Id. */
-  int FORWARD_SLASH = 3;
-  /** RegularExpression Id. */
-  int SP = 4;
-  /** RegularExpression Id. */
-  int HT = 5;
-  /** RegularExpression Id. */
-  int LWS = 6;
-  /** RegularExpression Id. */
-  int HTTP_TOKEN = 7;
-  /** RegularExpression Id. */
-  int QUOTED_STRING = 8;
-  /** RegularExpression Id. */
-  int START_QUOTE = 9;
-  /** RegularExpression Id. */
-  int HTTP_TOKEN_CHAR = 10;
-  /** RegularExpression Id. */
-  int QUOTED_TEXT = 11;
-  /** RegularExpression Id. */
-  int END_QUOTE = 12;
-  /** RegularExpression Id. */
-  int QUOTED_TEXT_CHAR = 13;
-  /** RegularExpression Id. */
-  int CHAR = 14;
-
-  /** Lexical state. */
-  int DEFAULT = 0;
-  /** Lexical state. */
-  int IN_QUOTED_TEXT = 1;
-
-  /** Literal token values. */
-  String[] tokenImage = {
-    "<EOF>",
-    "\";\"",
-    "\"=\"",
-    "\"/\"",
-    "\" \"",
-    "\"\\t\"",
-    "<LWS>",
-    "<HTTP_TOKEN>",
-    "<QUOTED_STRING>",
-    "\"\\\"\"",
-    "<HTTP_TOKEN_CHAR>",
-    "<QUOTED_TEXT>",
-    "\"\\\"\"",
-    "<QUOTED_TEXT_CHAR>",
-    "<CHAR>",
-  };
-
-}
diff --git a/java/org/apache/tomcat/util/http/parser/HttpParserTokenManager.java b/java/org/apache/tomcat/util/http/parser/HttpParserTokenManager.java
deleted file mode 100644
index c155a46..0000000
--- a/java/org/apache/tomcat/util/http/parser/HttpParserTokenManager.java
+++ /dev/null
@@ -1,465 +0,0 @@
-/* Generated By:JJTree&JavaCC: Do not edit this line. HttpParserTokenManager.java */
-package org.apache.tomcat.util.http.parser;
-
-/** Token Manager. */
- at SuppressWarnings("all") // Ignore warnings in generated code
-public class HttpParserTokenManager implements HttpParserConstants
-{
-
-  /** Debug output. */
-  public  java.io.PrintStream debugStream = System.out;
-  /** Set debug output. */
-  public  void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
-private final int jjStopStringLiteralDfa_0(int pos, long active0)
-{
-   switch (pos)
-   {
-      default :
-         return -1;
-   }
-}
-private final int jjStartNfa_0(int pos, long active0)
-{
-   return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
-}
-private int jjStopAtPos(int pos, int kind)
-{
-   jjmatchedKind = kind;
-   jjmatchedPos = pos;
-   return pos + 1;
-}
-private int jjMoveStringLiteralDfa0_0()
-{
-   switch(curChar)
-   {
-      case 9:
-         return jjStartNfaWithStates_0(0, 5, 12);
-      case 32:
-         return jjStartNfaWithStates_0(0, 4, 12);
-      case 34:
-         return jjStartNfaWithStates_0(0, 9, 13);
-      case 47:
-         return jjStopAtPos(0, 3);
-      case 59:
-         return jjStopAtPos(0, 1);
-      case 61:
-         return jjStopAtPos(0, 2);
-      default :
-         return jjMoveNfa_0(8, 0);
-   }
-}
-private int jjStartNfaWithStates_0(int pos, int kind, int state)
-{
-   jjmatchedKind = kind;
-   jjmatchedPos = pos;
-   try { curChar = input_stream.readChar(); }
-   catch(java.io.IOException e) { return pos + 1; }
-   return jjMoveNfa_0(state, pos + 1);
-}
-static final long[] jjbitVec0 = {
-   0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
-};
-private int jjMoveNfa_0(int startState, int curPos)
-{
-   int startsAt = 0;
-   jjnewStateCnt = 12;
-   int i = 1;
-   jjstateSet[0] = startState;
-   int kind = 0x7fffffff;
-   for (;;)
-   {
-      if (++jjround == 0x7fffffff)
-         ReInitRounds();
-      if (curChar < 64)
-      {
-         long l = 1L << curChar;
-         do
-         {
-            switch(jjstateSet[--i])
-            {
-               case 13:
-                  if ((0xfffffffb00000200L & l) != 0L)
-                     jjCheckNAddStates(0, 2);
-                  else if (curChar == 34)
-                  {
-                     if (kind > 8)
-                        kind = 8;
-                     jjCheckNAdd(7);
-                  }
-                  break;
-               case 12:
-                  if ((0x3ff6cfa00000000L & l) != 0L)
-                  {
-                     if (kind > 7)
-                        kind = 7;
-                     jjCheckNAddTwoStates(0, 1);
-                  }
-                  else if ((0x100000200L & l) != 0L)
-                     jjCheckNAddTwoStates(11, 2);
-                  else if (curChar == 34)
-                     jjCheckNAddStates(0, 2);
-                  if ((0x100000200L & l) != 0L)
-                     jjCheckNAddTwoStates(10, 0);
-                  if ((0x100000200L & l) != 0L)
-                  {
-                     if (kind > 6)
-                        kind = 6;
-                     jjCheckNAdd(9);
-                  }
-                  break;
-               case 8:
-                  if ((0x3ff6cfa00000000L & l) != 0L)
-                  {
-                     if (kind > 7)
-                        kind = 7;
-                     jjCheckNAddTwoStates(0, 1);
-                  }
-                  else if ((0x100000200L & l) != 0L)
-                  {
-                     if (kind > 6)
-                        kind = 6;
-                     jjCheckNAddStates(3, 7);
-                  }
-                  else if (curChar == 34)
-                     jjCheckNAddStates(0, 2);
-                  break;
-               case 0:
-                  if ((0x3ff6cfa00000000L & l) == 0L)
-                     break;
-                  if (kind > 7)
-                     kind = 7;
-                  jjCheckNAddTwoStates(0, 1);
-                  break;
-               case 1:
-                  if ((0x100000200L & l) == 0L)
-                     break;
-                  if (kind > 7)
-                     kind = 7;
-                  jjCheckNAdd(1);
-                  break;
-               case 2:
-                  if (curChar == 34)
-                     jjCheckNAddStates(0, 2);
-                  break;
-               case 3:
-                  if ((0xfffffffb00000200L & l) != 0L)
-                     jjCheckNAddStates(0, 2);
-                  break;
-               case 5:
-                  jjCheckNAddStates(0, 2);
-                  break;
-               case 6:
-                  if (curChar != 34)
-                     break;
-                  if (kind > 8)
-                     kind = 8;
-                  jjCheckNAdd(7);
-                  break;
-               case 7:
-                  if ((0x100000200L & l) == 0L)
-                     break;
-                  if (kind > 8)
-                     kind = 8;
-                  jjCheckNAdd(7);
-                  break;
-               case 9:
-                  if ((0x100000200L & l) == 0L)
-                     break;
-                  if (kind > 6)
-                     kind = 6;
-                  jjCheckNAdd(9);
-                  break;
-               case 10:
-                  if ((0x100000200L & l) != 0L)
-                     jjCheckNAddTwoStates(10, 0);
-                  break;
-               case 11:
-                  if ((0x100000200L & l) != 0L)
-                     jjCheckNAddTwoStates(11, 2);
-                  break;
-               default : break;
-            }
-         } while(i != startsAt);
-      }
-      else if (curChar < 128)
-      {
-         long l = 1L << (curChar & 077);
-         do
-         {
-            switch(jjstateSet[--i])
-            {
-               case 13:
-                  if ((0xffffffffefffffffL & l) != 0L)
-                     jjCheckNAddStates(0, 2);
-                  else if (curChar == 92)
-                     jjstateSet[jjnewStateCnt++] = 5;
-                  break;
-               case 12:
-               case 0:
-                  if ((0x57ffffffc7fffffeL & l) == 0L)
-                     break;
-                  if (kind > 7)
-                     kind = 7;
-                  jjCheckNAddTwoStates(0, 1);
-                  break;
-               case 8:
-                  if ((0x57ffffffc7fffffeL & l) == 0L)
-                     break;
-                  if (kind > 7)
-                     kind = 7;
-                  jjCheckNAddTwoStates(0, 1);
-                  break;
-               case 3:
-                  if ((0xffffffffefffffffL & l) != 0L)
-                     jjCheckNAddStates(0, 2);
-                  break;
-               case 4:
-                  if (curChar == 92)
-                     jjstateSet[jjnewStateCnt++] = 5;
-                  break;
-               case 5:
-                  jjCheckNAddStates(0, 2);
-                  break;
-               default : break;
-            }
-         } while(i != startsAt);
-      }
-      else
-      {
-         int hiByte = (int)(curChar >> 8);
-         int i1 = hiByte >> 6;
-         long l1 = 1L << (hiByte & 077);
-         int i2 = (curChar & 0xff) >> 6;
-         long l2 = 1L << (curChar & 077);
-         do
-         {
-            switch(jjstateSet[--i])
-            {
-               case 13:
-               case 3:
-                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
-                     jjCheckNAddStates(0, 2);
-                  break;
-               default : break;
-            }
-         } while(i != startsAt);
-      }
-      if (kind != 0x7fffffff)
-      {
-         jjmatchedKind = kind;
-         jjmatchedPos = curPos;
-         kind = 0x7fffffff;
-      }
-      ++curPos;
-      if ((i = jjnewStateCnt) == (startsAt = 12 - (jjnewStateCnt = startsAt)))
-         return curPos;
-      try { curChar = input_stream.readChar(); }
-      catch(java.io.IOException e) { return curPos; }
-   }
-}
-private int jjMoveStringLiteralDfa0_1()
-{
-   return 1;
-}
-static final int[] jjnextStates = {
-   3, 4, 6, 9, 10, 0, 11, 2,
-};
-private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2)
-{
-   switch(hiByte)
-   {
-      case 0:
-         return ((jjbitVec0[i2] & l2) != 0L);
-      default :
-         return false;
-   }
-}
-
-/** Token literal values. */
-public static final String[] jjstrLiteralImages = {
-"", "\73", "\75", "\57", "\40", "\11", null, null, null, "\42", null, null,
-null, null, null, };
-
-/** Lexer state names. */
-public static final String[] lexStateNames = {
-   "DEFAULT",
-   "IN_QUOTED_TEXT",
-};
-
-/** Lex State array. */
-public static final int[] jjnewLexState = {
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1,
-};
-protected SimpleCharStream input_stream;
-private final int[] jjrounds = new int[12];
-private final int[] jjstateSet = new int[24];
-protected char curChar;
-/** Constructor. */
-public HttpParserTokenManager(SimpleCharStream stream){
-   if (SimpleCharStream.staticFlag)
-      throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
-   input_stream = stream;
-}
-
-/** Constructor. */
-public HttpParserTokenManager(SimpleCharStream stream, int lexState){
-   this(stream);
-   SwitchTo(lexState);
-}
-
-/** Reinitialise parser. */
-public void ReInit(SimpleCharStream stream)
-{
-   jjmatchedPos = jjnewStateCnt = 0;
-   curLexState = defaultLexState;
-   input_stream = stream;
-   ReInitRounds();
-}
-private void ReInitRounds()
-{
-   int i;
-   jjround = 0x80000001;
-   for (i = 12; i-- > 0;)
-      jjrounds[i] = 0x80000000;
-}
-
-/** Reinitialise parser. */
-public void ReInit(SimpleCharStream stream, int lexState)
-{
-   ReInit(stream);
-   SwitchTo(lexState);
-}
-
-/** Switch to specified lex state. */
-public void SwitchTo(int lexState)
-{
-   if (lexState >= 2 || lexState < 0)
-      throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
-   else
-      curLexState = lexState;
-}
-
-protected Token jjFillToken()
-{
-   final Token t;
-   final String curTokenImage;
-   final int beginLine;
-   final int endLine;
-   final int beginColumn;
-   final int endColumn;
-   String im = jjstrLiteralImages[jjmatchedKind];
-   curTokenImage = (im == null) ? input_stream.GetImage() : im;
-   beginLine = input_stream.getBeginLine();
-   beginColumn = input_stream.getBeginColumn();
-   endLine = input_stream.getEndLine();
-   endColumn = input_stream.getEndColumn();
-   t = Token.newToken(jjmatchedKind, curTokenImage);
-
-   t.beginLine = beginLine;
-   t.endLine = endLine;
-   t.beginColumn = beginColumn;
-   t.endColumn = endColumn;
-
-   return t;
-}
-
-int curLexState = 0;
-int defaultLexState = 0;
-int jjnewStateCnt;
-int jjround;
-int jjmatchedPos;
-int jjmatchedKind;
-
-/** Get the next Token. */
-public Token getNextToken()
-{
-  Token matchedToken;
-  int curPos = 0;
-
-  EOFLoop :
-  for (;;)
-  {
-   try
-   {
-      curChar = input_stream.BeginToken();
-   }
-   catch(java.io.IOException e)
-   {
-      jjmatchedKind = 0;
-      matchedToken = jjFillToken();
-      return matchedToken;
-   }
-
-   switch(curLexState)
-   {
-     case 0:
-       jjmatchedKind = 0x7fffffff;
-       jjmatchedPos = 0;
-       curPos = jjMoveStringLiteralDfa0_0();
-       break;
-     case 1:
-       jjmatchedKind = 0x7fffffff;
-       jjmatchedPos = 0;
-       curPos = jjMoveStringLiteralDfa0_1();
-       break;
-   }
-     if (jjmatchedKind != 0x7fffffff)
-     {
-        if (jjmatchedPos + 1 < curPos)
-           input_stream.backup(curPos - jjmatchedPos - 1);
-           matchedToken = jjFillToken();
-       if (jjnewLexState[jjmatchedKind] != -1)
-         curLexState = jjnewLexState[jjmatchedKind];
-           return matchedToken;
-     }
-     int error_line = input_stream.getEndLine();
-     int error_column = input_stream.getEndColumn();
-     String error_after = null;
-     boolean EOFSeen = false;
-     try { input_stream.readChar(); input_stream.backup(1); }
-     catch (java.io.IOException e1) {
-        EOFSeen = true;
-        error_after = curPos <= 1 ? "" : input_stream.GetImage();
-        if (curChar == '\n' || curChar == '\r') {
-           error_line++;
-           error_column = 0;
-        }
-        else
-           error_column++;
-     }
-     if (!EOFSeen) {
-        input_stream.backup(1);
-        error_after = curPos <= 1 ? "" : input_stream.GetImage();
-     }
-     throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
-  }
-}
-
-private void jjCheckNAdd(int state)
-{
-   if (jjrounds[state] != jjround)
-   {
-      jjstateSet[jjnewStateCnt++] = state;
-      jjrounds[state] = jjround;
-   }
-}
-private void jjAddStates(int start, int end)
-{
-   do {
-      jjstateSet[jjnewStateCnt++] = jjnextStates[start];
-   } while (start++ != end);
-}
-private void jjCheckNAddTwoStates(int state1, int state2)
-{
-   jjCheckNAdd(state1);
-   jjCheckNAdd(state2);
-}
-
-private void jjCheckNAddStates(int start, int end)
-{
-   do {
-      jjCheckNAdd(jjnextStates[start]);
-   } while (start++ != end);
-}
-
-}
diff --git a/java/org/apache/tomcat/util/http/parser/HttpParserTreeConstants.java b/java/org/apache/tomcat/util/http/parser/HttpParserTreeConstants.java
deleted file mode 100644
index 615c56c..0000000
--- a/java/org/apache/tomcat/util/http/parser/HttpParserTreeConstants.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. HttpParserTreeConstants.java Version 5.0 */
-package org.apache.tomcat.util.http.parser;
-
-public interface HttpParserTreeConstants
-{
-  public int JJTMEDIATYPE = 0;
-  public int JJTTYPE = 1;
-  public int JJTSUBTYPE = 2;
-  public int JJTPARAMETER = 3;
-  public int JJTATTRIBUTE = 4;
-  public int JJTVALUE = 5;
-
-
-  public String[] jjtNodeName = {
-    "MediaType",
-    "Type",
-    "SubType",
-    "Parameter",
-    "Attribute",
-    "Value",
-  };
-}
-/* JavaCC - OriginalChecksum=f4745df783771bdbdddd3be661f1c089 (do not edit this line) */
diff --git a/java/org/apache/tomcat/util/http/parser/JJTHttpParserState.java b/java/org/apache/tomcat/util/http/parser/JJTHttpParserState.java
deleted file mode 100644
index 5b20ba3..0000000
--- a/java/org/apache/tomcat/util/http/parser/JJTHttpParserState.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. JJTHttpParserState.java Version 5.0 */
-package org.apache.tomcat.util.http.parser;
-
- at SuppressWarnings("all") // Ignore warnings in generated code
-public class JJTHttpParserState {
-  private java.util.List<Node> nodes;
-  private java.util.List<Integer> marks;
-
-  private int sp;        // number of nodes on stack
-  private int mk;        // current mark
-  private boolean node_created;
-
-  public JJTHttpParserState() {
-    nodes = new java.util.ArrayList<Node>();
-    marks = new java.util.ArrayList<Integer>();
-    sp = 0;
-    mk = 0;
-  }
-
-  /* Determines whether the current node was actually closed and
-     pushed.  This should only be called in the final user action of a
-     node scope.  */
-  public boolean nodeCreated() {
-    return node_created;
-  }
-
-  /* Call this to reinitialize the node stack.  It is called
-     automatically by the parser's ReInit() method. */
-  public void reset() {
-    nodes.clear();
-    marks.clear();
-    sp = 0;
-    mk = 0;
-  }
-
-  /* Returns the root node of the AST.  It only makes sense to call
-     this after a successful parse. */
-  public Node rootNode() {
-    return nodes.get(0);
-  }
-
-  /* Pushes a node on to the stack. */
-  public void pushNode(Node n) {
-    nodes.add(n);
-    ++sp;
-  }
-
-  /* Returns the node on the top of the stack, and remove it from the
-     stack.  */
-  public Node popNode() {
-    if (--sp < mk) {
-      mk = marks.remove(marks.size()-1);
-    }
-    return nodes.remove(nodes.size()-1);
-  }
-
-  /* Returns the node currently on the top of the stack. */
-  public Node peekNode() {
-    return nodes.get(nodes.size()-1);
-  }
-
-  /* Returns the number of children on the stack in the current node
-     scope. */
-  public int nodeArity() {
-    return sp - mk;
-  }
-
-
-  public void clearNodeScope(Node n) {
-    while (sp > mk) {
-      popNode();
-    }
-    mk = marks.remove(marks.size()-1);
-  }
-
-
-  public void openNodeScope(Node n) {
-    marks.add(mk);
-    mk = sp;
-    n.jjtOpen();
-  }
-
-
-  /* A definite node is constructed from a specified number of
-     children.  That number of nodes are popped from the stack and
-     made the children of the definite node.  Then the definite node
-     is pushed on to the stack. */
-  public void closeNodeScope(Node n, int num) {
-    mk = marks.remove(marks.size()-1);
-    while (num-- > 0) {
-      Node c = popNode();
-      c.jjtSetParent(n);
-      n.jjtAddChild(c, num);
-    }
-    n.jjtClose();
-    pushNode(n);
-    node_created = true;
-  }
-
-
-  /* A conditional node is constructed if its condition is true.  All
-     the nodes that have been pushed since the node was opened are
-     made children of the conditional node, which is then pushed
-     on to the stack.  If the condition is false the node is not
-     constructed and they are left on the stack. */
-  public void closeNodeScope(Node n, boolean condition) {
-    if (condition) {
-      int a = nodeArity();
-      mk = marks.remove(marks.size()-1);
-      while (a-- > 0) {
-        Node c = popNode();
-        c.jjtSetParent(n);
-        n.jjtAddChild(c, a);
-      }
-      n.jjtClose();
-      pushNode(n);
-      node_created = true;
-    } else {
-      mk = marks.remove(marks.size()-1);
-      node_created = false;
-    }
-  }
-}
-/* JavaCC - OriginalChecksum=ddd6baff0afccf0891566804931f534d (do not edit this line) */
diff --git a/java/org/apache/tomcat/util/http/parser/MediaType.java b/java/org/apache/tomcat/util/http/parser/MediaType.java
new file mode 100644
index 0000000..dbee0f6
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/parser/MediaType.java
@@ -0,0 +1,125 @@
+/*
+ *  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.tomcat.util.http.parser;
+
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class MediaType {
+
+    private final String type;
+    private final String subtype;
+    private final LinkedHashMap<String,String> parameters;
+    private final String charset;
+    private volatile String noCharset;
+    private volatile String withCharset;
+
+    protected MediaType(String type, String subtype,
+            LinkedHashMap<String,String> parameters) {
+        this.type = type;
+        this.subtype = subtype;
+        this.parameters = parameters;
+
+        String cs = parameters.get("charset");
+        if (cs != null && cs.length() > 0 &&
+                cs.charAt(0) == '"') {
+            cs = HttpParser.unquote(cs);
+        }
+        this.charset = cs;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getSubtype() {
+        return subtype;
+    }
+
+    public String getCharset() {
+        return charset;
+    }
+
+    public int getParameterCount() {
+        return parameters.size();
+    }
+
+    public String getParameterValue(String parameter) {
+        return parameters.get(parameter.toLowerCase(Locale.US));
+    }
+
+    @Override
+    public String toString() {
+        if (withCharset == null) {
+            synchronized (this) {
+                if (withCharset == null) {
+                    StringBuilder result = new StringBuilder();
+                    result.append(type);
+                    result.append('/');
+                    result.append(subtype);
+                    for (Map.Entry<String, String> entry : parameters.entrySet()) {
+                        String value = entry.getValue();
+                        if (value == null || value.length() == 0) {
+                            continue;
+                        }
+                        result.append(';');
+                        // Workaround for Adobe Read 9 plug-in on IE bug
+                        // Can be removed after 26 June 2013 (EOL of Reader 9)
+                        // See BZ 53814
+                        result.append(' ');
+                        result.append(entry.getKey());
+                        result.append('=');
+                        result.append(value);
+                    }
+
+                    withCharset = result.toString();
+                }
+            }
+        }
+        return withCharset;
+    }
+
+    public String toStringNoCharset() {
+        if (noCharset == null) {
+            synchronized (this) {
+                if (noCharset == null) {
+                    StringBuilder result = new StringBuilder();
+                    result.append(type);
+                    result.append('/');
+                    result.append(subtype);
+                    for (Map.Entry<String, String> entry : parameters.entrySet()) {
+                        if (entry.getKey().equalsIgnoreCase("charset")) {
+                            continue;
+                        }
+                        result.append(';');
+                        // Workaround for Adobe Read 9 plug-in on IE bug
+                        // Can be removed after 26 June 2013 (EOL of Reader 9)
+                        // See BZ 53814
+                        result.append(' ');
+                        result.append(entry.getKey());
+                        result.append('=');
+                        result.append(entry.getValue());
+                    }
+
+                    noCharset = result.toString();
+                }
+            }
+        }
+        return noCharset;
+    }
+}
diff --git a/java/org/apache/tomcat/util/http/parser/MediaTypeCache.java b/java/org/apache/tomcat/util/http/parser/MediaTypeCache.java
new file mode 100644
index 0000000..efed85c
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/parser/MediaTypeCache.java
@@ -0,0 +1,65 @@
+/*
+ *  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.tomcat.util.http.parser;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import org.apache.tomcat.util.collections.ConcurrentCache;
+
+/**
+ * Caches the results of parsing content-type headers.
+ */
+public class MediaTypeCache {
+
+    private final ConcurrentCache<String,String[]> cache;
+
+    public MediaTypeCache(int size) {
+        cache = new ConcurrentCache<String,String[]>(size);
+    }
+
+    /**
+     * Looks in the cache and returns the cached value if one is present. If no
+     * match exists in the cache, a new parser is created, the input parsed and
+     * the results placed in the cache and returned to the user.
+     *
+     * @param input The content-type header value to parse
+     * @return      The results are provided as a two element String array. The
+     *                  first element is the media type less the charset and
+     *                  the second element is the charset
+     */
+    public String[] parse(String input) {
+        String[] result = cache.get(input);
+
+        if (result != null) {
+            return result;
+        }
+
+        MediaType m = null;
+        try {
+            m = HttpParser.parseMediaType(new StringReader(input));
+        } catch (IOException e) {
+            // Ignore - return null
+        }
+        if (m != null) {
+            result = new String[] {m.toStringNoCharset(), m.getCharset()};
+            cache.put(input, result);
+        }
+
+        return result;
+    }
+}
diff --git a/java/org/apache/tomcat/util/http/parser/Node.java b/java/org/apache/tomcat/util/http/parser/Node.java
deleted file mode 100644
index 6aaaba4..0000000
--- a/java/org/apache/tomcat/util/http/parser/Node.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *  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.tomcat.util.http.parser;
-
-/* All AST nodes must implement this interface.  It provides basic
- machinery for constructing the parent and child relationships
- between nodes. */
-
-public interface Node {
-
-    /**
-     * This method is called after the node has been made the current node. It
-     * indicates that child nodes can now be added to it.
-     */
-    public void jjtOpen();
-
-    /**
-     * This method is called after all the child nodes have been added.
-     */
-    public void jjtClose();
-
-    /**
-     * This pair of methods are used to inform the node of its parent.
-     */
-    public void jjtSetParent(Node n);
-
-    public Node jjtGetParent();
-
-    /**
-     * This method tells the node to add its argument to the node's list of
-     * children.
-     */
-    public void jjtAddChild(Node n, int i);
-
-    /**
-     * This method returns a child node. The children are numbered from zero,
-     * left to right.
-     */
-    public Node jjtGetChild(int i);
-
-    /** Return the number of children the node has. */
-    public int jjtGetNumChildren();
-
-    public Object jjtGetValue();
-}
diff --git a/java/org/apache/tomcat/util/http/parser/ParseException.java b/java/org/apache/tomcat/util/http/parser/ParseException.java
deleted file mode 100644
index 4e0e2df..0000000
--- a/java/org/apache/tomcat/util/http/parser/ParseException.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 5.0 */
-/* JavaCCOptions:KEEP_LINE_COL=null */
-package org.apache.tomcat.util.http.parser;
-
-/**
- * This exception is thrown when parse errors are encountered.
- * You can explicitly create objects of this exception type by
- * calling the method generateParseException in the generated
- * parser.
- *
- * You can modify this class to customize your error reporting
- * mechanisms so long as you retain the public fields.
- */
-public class ParseException extends Exception {
-
-  /**
-   * The version identifier for this Serializable class.
-   * Increment only if the <i>serialized</i> form of the
-   * class changes.
-   */
-  private static final long serialVersionUID = 1L;
-
-  /**
-   * This constructor is used by the method "generateParseException"
-   * in the generated parser.  Calling this constructor generates
-   * a new object of this type with the fields "currentToken",
-   * "expectedTokenSequences", and "tokenImage" set.
-   */
-  public ParseException(Token currentTokenVal,
-                        int[][] expectedTokenSequencesVal,
-                        String[] tokenImageVal
-                       )
-  {
-    super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
-    currentToken = currentTokenVal;
-    expectedTokenSequences = expectedTokenSequencesVal;
-    tokenImage = tokenImageVal;
-  }
-
-  /**
-   * The following constructors are for use by you for whatever
-   * purpose you can think of.  Constructing the exception in this
-   * manner makes the exception behave in the normal way - i.e., as
-   * documented in the class "Throwable".  The fields "errorToken",
-   * "expectedTokenSequences", and "tokenImage" do not contain
-   * relevant information.  The JavaCC generated code does not use
-   * these constructors.
-   */
-
-  public ParseException() {
-    super();
-  }
-
-  /** Constructor with message. */
-  public ParseException(String message) {
-    super(message);
-  }
-
-
-  /**
-   * This is the last token that has been consumed successfully.  If
-   * this object has been created due to a parse error, the token
-   * followng this token will (therefore) be the first error token.
-   */
-  public Token currentToken;
-
-  /**
-   * Each entry in this array is an array of integers.  Each array
-   * of integers represents a sequence of tokens (by their ordinal
-   * values) that is expected at this point of the parse.
-   */
-  public int[][] expectedTokenSequences;
-
-  /**
-   * This is a reference to the "tokenImage" array of the generated
-   * parser within which the parse error occurred.  This array is
-   * defined in the generated ...Constants interface.
-   */
-  public String[] tokenImage;
-
-  /**
-   * It uses "currentToken" and "expectedTokenSequences" to generate a parse
-   * error message and returns it.  If this object has been created
-   * due to a parse error, and you do not catch it (it gets thrown
-   * from the parser) the correct error message
-   * gets displayed.
-   */
-  private static String initialise(Token currentToken,
-                           int[][] expectedTokenSequences,
-                           String[] tokenImage) {
-    String eol = System.getProperty("line.separator", "\n");
-    StringBuffer expected = new StringBuffer();
-    int maxSize = 0;
-    for (int i = 0; i < expectedTokenSequences.length; i++) {
-      if (maxSize < expectedTokenSequences[i].length) {
-        maxSize = expectedTokenSequences[i].length;
-      }
-      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
-        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
-      }
-      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
-        expected.append("...");
-      }
-      expected.append(eol).append("    ");
-    }
-    String retval = "Encountered \"";
-    Token tok = currentToken.next;
-    for (int i = 0; i < maxSize; i++) {
-      if (i != 0) retval += " ";
-      if (tok.kind == 0) {
-        retval += tokenImage[0];
-        break;
-      }
-      retval += " " + tokenImage[tok.kind];
-      retval += " \"";
-      retval += add_escapes(tok.image);
-      retval += " \"";
-      tok = tok.next;
-    }
-    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
-    retval += "." + eol;
-    if (expectedTokenSequences.length == 1) {
-      retval += "Was expecting:" + eol + "    ";
-    } else {
-      retval += "Was expecting one of:" + eol + "    ";
-    }
-    retval += expected.toString();
-    return retval;
-  }
-
-  /**
-   * The end of line string for this machine.
-   */
-  protected String eol = System.getProperty("line.separator", "\n");
-
-  /**
-   * Used to convert raw characters to their escaped version
-   * when these raw version cannot be used as part of an ASCII
-   * string literal.
-   */
-  static String add_escapes(String str) {
-      StringBuffer retval = new StringBuffer();
-      char ch;
-      for (int i = 0; i < str.length(); i++) {
-        switch (str.charAt(i))
-        {
-           case 0 :
-              continue;
-           case '\b':
-              retval.append("\\b");
-              continue;
-           case '\t':
-              retval.append("\\t");
-              continue;
-           case '\n':
-              retval.append("\\n");
-              continue;
-           case '\f':
-              retval.append("\\f");
-              continue;
-           case '\r':
-              retval.append("\\r");
-              continue;
-           case '\"':
-              retval.append("\\\"");
-              continue;
-           case '\'':
-              retval.append("\\\'");
-              continue;
-           case '\\':
-              retval.append("\\\\");
-              continue;
-           default:
-              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
-                 String s = "0000" + Integer.toString(ch, 16);
-                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
-              } else {
-                 retval.append(ch);
-              }
-              continue;
-        }
-      }
-      return retval.toString();
-   }
-
-}
-/* JavaCC - OriginalChecksum=a5bfbb99e4df5e108e0f9a6351af5364 (do not edit this line) */
diff --git a/java/org/apache/tomcat/util/http/parser/SimpleCharStream.java b/java/org/apache/tomcat/util/http/parser/SimpleCharStream.java
deleted file mode 100644
index 2c7b69e..0000000
--- a/java/org/apache/tomcat/util/http/parser/SimpleCharStream.java
+++ /dev/null
@@ -1,471 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
-/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
-package org.apache.tomcat.util.http.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. */
-  public static final boolean staticFlag = false;
-  int bufsize;
-  int available;
-  int tokenBegin;
-/** Position in buffer. */
-  public int bufpos = -1;
-  protected int bufline[];
-  protected int bufcolumn[];
-
-  protected int column = 0;
-  protected int line = 1;
-
-  protected boolean prevCharIsCR = false;
-  protected boolean prevCharIsLF = false;
-
-  protected java.io.Reader inputStream;
-
-  protected char[] buffer;
-  protected int maxNextCharInd = 0;
-  protected int inBuf = 0;
-  protected int tabSize = 8;
-
-  protected void setTabSize(int i) { tabSize = i; }
-  protected int getTabSize(int i) { return tabSize; }
-
-
-  protected void ExpandBuff(boolean wrapAround)
-  {
-    char[] newbuffer = new char[bufsize + 2048];
-    int newbufline[] = new int[bufsize + 2048];
-    int newbufcolumn[] = new int[bufsize + 2048];
-
-    try
-    {
-      if (wrapAround)
-      {
-        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
-        System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
-        buffer = newbuffer;
-
-        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
-        System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
-        bufline = newbufline;
-
-        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
-        System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
-        bufcolumn = newbufcolumn;
-
-        maxNextCharInd = (bufpos += (bufsize - tokenBegin));
-      }
-      else
-      {
-        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
-        buffer = newbuffer;
-
-        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
-        bufline = newbufline;
-
-        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
-        bufcolumn = newbufcolumn;
-
-        maxNextCharInd = (bufpos -= tokenBegin);
-      }
-    }
-    catch (Throwable t)
-    {
-      throw new Error(t.getMessage());
-    }
-
-
-    bufsize += 2048;
-    available = bufsize;
-    tokenBegin = 0;
-  }
-
-  protected void FillBuff() throws java.io.IOException
-  {
-    if (maxNextCharInd == available)
-    {
-      if (available == bufsize)
-      {
-        if (tokenBegin > 2048)
-        {
-          bufpos = maxNextCharInd = 0;
-          available = tokenBegin;
-        }
-        else if (tokenBegin < 0)
-          bufpos = maxNextCharInd = 0;
-        else
-          ExpandBuff(false);
-      }
-      else if (available > tokenBegin)
-        available = bufsize;
-      else if ((tokenBegin - available) < 2048)
-        ExpandBuff(true);
-      else
-        available = tokenBegin;
-    }
-
-    int i;
-    try {
-      if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
-      {
-        inputStream.close();
-        throw new java.io.IOException();
-      }
-      else
-        maxNextCharInd += i;
-      return;
-    }
-    catch(java.io.IOException e) {
-      --bufpos;
-      backup(0);
-      if (tokenBegin == -1)
-        tokenBegin = bufpos;
-      throw e;
-    }
-  }
-
-/** Start. */
-  public char BeginToken() throws java.io.IOException
-  {
-    tokenBegin = -1;
-    char c = readChar();
-    tokenBegin = bufpos;
-
-    return c;
-  }
-
-  protected void UpdateLineColumn(char c)
-  {
-    column++;
-
-    if (prevCharIsLF)
-    {
-      prevCharIsLF = false;
-      line += (column = 1);
-    }
-    else if (prevCharIsCR)
-    {
-      prevCharIsCR = false;
-      if (c == '\n')
-      {
-        prevCharIsLF = true;
-      }
-      else
-        line += (column = 1);
-    }
-
-    switch (c)
-    {
-      case '\r' :
-        prevCharIsCR = true;
-        break;
-      case '\n' :
-        prevCharIsLF = true;
-        break;
-      case '\t' :
-        column--;
-        column += (tabSize - (column % tabSize));
-        break;
-      default :
-        break;
-    }
-
-    bufline[bufpos] = line;
-    bufcolumn[bufpos] = column;
-  }
-
-/** Read a character. */
-  public char readChar() throws java.io.IOException
-  {
-    if (inBuf > 0)
-    {
-      --inBuf;
-
-      if (++bufpos == bufsize)
-        bufpos = 0;
-
-      return buffer[bufpos];
-    }
-
-    if (++bufpos >= maxNextCharInd)
-      FillBuff();
-
-    char c = buffer[bufpos];
-
-    UpdateLineColumn(c);
-    return c;
-  }
-
-  @Deprecated
-  /**
-   * @deprecated
-   * @see #getEndColumn
-   */
-
-  public int getColumn() {
-    return bufcolumn[bufpos];
-  }
-
-  @Deprecated
-  /**
-   * @deprecated
-   * @see #getEndLine
-   */
-
-  public int getLine() {
-    return bufline[bufpos];
-  }
-
-  /** Get token end column number. */
-  public int getEndColumn() {
-    return bufcolumn[bufpos];
-  }
-
-  /** Get token end line number. */
-  public int getEndLine() {
-     return bufline[bufpos];
-  }
-
-  /** Get token beginning column number. */
-  public int getBeginColumn() {
-    return bufcolumn[tokenBegin];
-  }
-
-  /** Get token beginning line number. */
-  public int getBeginLine() {
-    return bufline[tokenBegin];
-  }
-
-/** Backup a number of characters. */
-  public void backup(int amount) {
-
-    inBuf += amount;
-    if ((bufpos -= amount) < 0)
-      bufpos += bufsize;
-  }
-
-  /** Constructor. */
-  public SimpleCharStream(java.io.Reader dstream, int startline,
-  int startcolumn, int buffersize)
-  {
-    inputStream = dstream;
-    line = startline;
-    column = startcolumn - 1;
-
-    available = bufsize = buffersize;
-    buffer = new char[buffersize];
-    bufline = new int[buffersize];
-    bufcolumn = new int[buffersize];
-  }
-
-  /** Constructor. */
-  public SimpleCharStream(java.io.Reader dstream, int startline,
-                          int startcolumn)
-  {
-    this(dstream, startline, startcolumn, 4096);
-  }
-
-  /** Constructor. */
-  public SimpleCharStream(java.io.Reader dstream)
-  {
-    this(dstream, 1, 1, 4096);
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.Reader dstream, int startline,
-  int startcolumn, int buffersize)
-  {
-    inputStream = dstream;
-    line = startline;
-    column = startcolumn - 1;
-
-    if (buffer == null || buffersize != buffer.length)
-    {
-      available = bufsize = buffersize;
-      buffer = new char[buffersize];
-      bufline = new int[buffersize];
-      bufcolumn = new int[buffersize];
-    }
-    prevCharIsLF = prevCharIsCR = false;
-    tokenBegin = inBuf = maxNextCharInd = 0;
-    bufpos = -1;
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.Reader dstream, int startline,
-                     int startcolumn)
-  {
-    ReInit(dstream, startline, startcolumn, 4096);
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.Reader dstream)
-  {
-    ReInit(dstream, 1, 1, 4096);
-  }
-  /** Constructor. */
-  public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
-  int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
-  {
-    this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
-  }
-
-  /** Constructor. */
-  public SimpleCharStream(java.io.InputStream dstream, int startline,
-  int startcolumn, int buffersize)
-  {
-    this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
-  }
-
-  /** Constructor. */
-  public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
-                          int startcolumn) throws java.io.UnsupportedEncodingException
-  {
-    this(dstream, encoding, startline, startcolumn, 4096);
-  }
-
-  /** Constructor. */
-  public SimpleCharStream(java.io.InputStream dstream, int startline,
-                          int startcolumn)
-  {
-    this(dstream, startline, startcolumn, 4096);
-  }
-
-  /** Constructor. */
-  public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
-  {
-    this(dstream, encoding, 1, 1, 4096);
-  }
-
-  /** Constructor. */
-  public SimpleCharStream(java.io.InputStream dstream)
-  {
-    this(dstream, 1, 1, 4096);
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.InputStream dstream, String encoding, int startline,
-                          int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
-  {
-    ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.InputStream dstream, int startline,
-                          int startcolumn, int buffersize)
-  {
-    ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
-  {
-    ReInit(dstream, encoding, 1, 1, 4096);
-  }
-
-  /** Reinitialise. */
-  public void ReInit(java.io.InputStream dstream)
-  {
-    ReInit(dstream, 1, 1, 4096);
-  }
-  /** Reinitialise. */
-  public void ReInit(java.io.InputStream dstream, String encoding, int startline,
-                     int startcolumn) throws java.io.UnsupportedEncodingException
-  {
-    ReInit(dstream, encoding, startline, startcolumn, 4096);
-  }
-  /** Reinitialise. */
-  public void ReInit(java.io.InputStream dstream, int startline,
-                     int startcolumn)
-  {
-    ReInit(dstream, startline, startcolumn, 4096);
-  }
-  /** Get token literal value. */
-  public String GetImage()
-  {
-    if (bufpos >= tokenBegin)
-      return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
-    else
-      return new String(buffer, tokenBegin, bufsize - tokenBegin) +
-                            new String(buffer, 0, bufpos + 1);
-  }
-
-  /** Get the suffix. */
-  public char[] GetSuffix(int len)
-  {
-    char[] ret = new char[len];
-
-    if ((bufpos + 1) >= len)
-      System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
-    else
-    {
-      System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
-                                                        len - bufpos - 1);
-      System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
-    }
-
-    return ret;
-  }
-
-  /** Reset buffer when finished. */
-  public void Done()
-  {
-    buffer = null;
-    bufline = null;
-    bufcolumn = null;
-  }
-
-  /**
-   * Method to adjust line and column numbers for the start of a token.
-   */
-  public void adjustBeginLineColumn(int newLine, int newCol)
-  {
-    int start = tokenBegin;
-    int len;
-
-    if (bufpos >= tokenBegin)
-    {
-      len = bufpos - tokenBegin + inBuf + 1;
-    }
-    else
-    {
-      len = bufsize - tokenBegin + bufpos + 1 + inBuf;
-    }
-
-    int i = 0, j = 0, k = 0;
-    int nextColDiff = 0, columnDiff = 0;
-
-    while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
-    {
-      bufline[j] = newLine;
-      nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
-      bufcolumn[j] = newCol + columnDiff;
-      columnDiff = nextColDiff;
-      i++;
-    }
-
-    if (i < len)
-    {
-      bufline[j] = newLine++;
-      bufcolumn[j] = newCol + columnDiff;
-
-      while (i++ < len)
-      {
-        if (bufline[j = start % bufsize] != bufline[++start % bufsize])
-          bufline[j] = newLine++;
-        else
-          bufline[j] = newLine;
-      }
-    }
-
-    line = bufline[j];
-    column = bufcolumn[j];
-  }
-
-}
-/* JavaCC - OriginalChecksum=d7e5626d3f8464d1815f1157b0223728 (do not edit this line) */
diff --git a/java/org/apache/tomcat/util/http/parser/SimpleNode.java b/java/org/apache/tomcat/util/http/parser/SimpleNode.java
deleted file mode 100644
index c401bb0..0000000
--- a/java/org/apache/tomcat/util/http/parser/SimpleNode.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- *  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.tomcat.util.http.parser;
-
-public class SimpleNode implements Node {
-
-    protected Node parent;
-    protected Node[] children;
-    protected int id;
-    protected Object value;
-    protected HttpParser parser;
-
-    public SimpleNode(int i) {
-        id = i;
-    }
-
-    public SimpleNode(HttpParser p, int i) {
-        this(i);
-        parser = p;
-    }
-
-    @Override
-    public void jjtOpen() {
-        // NOOP
-    }
-
-    @Override
-    public void jjtClose() {
-        // NOOP
-    }
-
-    @Override
-    public void jjtSetParent(Node n) {
-        parent = n;
-    }
-
-    @Override
-    public Node jjtGetParent() {
-        return parent;
-    }
-
-    @Override
-    public void jjtAddChild(Node n, int i) {
-        if (children == null) {
-            children = new Node[i + 1];
-        } else if (i >= children.length) {
-            Node c[] = new Node[i + 1];
-            System.arraycopy(children, 0, c, 0, children.length);
-            children = c;
-        }
-        children[i] = n;
-    }
-
-    @Override
-    public Node jjtGetChild(int i) {
-        return children[i];
-    }
-
-    @Override
-    public int jjtGetNumChildren() {
-        return (children == null) ? 0 : children.length;
-    }
-
-    public void jjtSetValue(Object value) {
-        this.value = value;
-    }
-
-    @Override
-    public Object jjtGetValue() {
-        return value;
-    }
-
-    /*
-     * You can override these two methods in subclasses of SimpleNode to
-     * customize the way the node appears when the tree is dumped. If your
-     * output uses more than one line you should override toString(String),
-     * otherwise overriding toString() is probably all you need to do.
-     */
-    @Override
-    public String toString() {
-        return HttpParserTreeConstants.jjtNodeName[id];
-    }
-
-    public String toString(String prefix) {
-        return prefix + toString();
-    }
-
-    /*
-     * Override this method if you want to customize how the node dumps out its
-     * children.
-     */
-    public void dump(String prefix) {
-        System.out.println(toString(prefix));
-        if (children != null) {
-            for (int i = 0; i < children.length; ++i) {
-                SimpleNode n = (SimpleNode) children[i];
-                if (n != null) {
-                    n.dump(prefix + " ");
-                }
-            }
-        }
-    }
-}
-
diff --git a/java/org/apache/tomcat/util/http/parser/Token.java b/java/org/apache/tomcat/util/http/parser/Token.java
deleted file mode 100644
index 43687b0..0000000
--- a/java/org/apache/tomcat/util/http/parser/Token.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
-/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
-package org.apache.tomcat.util.http.parser;
-
-/**
- * Describes the input token stream.
- */
- at SuppressWarnings("all") // Ignore warnings in generated code
-public class Token implements java.io.Serializable {
-
-  /**
-   * The version identifier for this Serializable class.
-   * Increment only if the <i>serialized</i> form of the
-   * class changes.
-   */
-  private static final long serialVersionUID = 1L;
-
-  /**
-   * An integer that describes the kind of this token.  This numbering
-   * system is determined by JavaCCParser, and a table of these numbers is
-   * stored in the file ...Constants.java.
-   */
-  public int kind;
-
-  /** The line number of the first character of this Token. */
-  public int beginLine;
-  /** The column number of the first character of this Token. */
-  public int beginColumn;
-  /** The line number of the last character of this Token. */
-  public int endLine;
-  /** The column number of the last character of this Token. */
-  public int endColumn;
-
-  /**
-   * The string image of the token.
-   */
-  public String image;
-
-  /**
-   * A reference to the next regular (non-special) token from the input
-   * stream.  If this is the last token from the input stream, or if the
-   * token manager has not read tokens beyond this one, this field is
-   * set to null.  This is true only if this token is also a regular
-   * token.  Otherwise, see below for a description of the contents of
-   * this field.
-   */
-  public Token next;
-
-  /**
-   * This field is used to access special tokens that occur prior to this
-   * token, but after the immediately preceding regular (non-special) token.
-   * If there are no such special tokens, this field is set to null.
-   * When there are more than one such special token, this field refers
-   * to the last of these special tokens, which in turn refers to the next
-   * previous special token through its specialToken field, and so on
-   * until the first special token (whose specialToken field is null).
-   * The next fields of special tokens refer to other special tokens that
-   * immediately follow it (without an intervening regular token).  If there
-   * is no such token, this field is null.
-   */
-  public Token specialToken;
-
-  /**
-   * An optional attribute value of the Token.
-   * Tokens which are not used as syntactic sugar will often contain
-   * meaningful values that will be used later on by the compiler or
-   * interpreter. This attribute value is often different from the image.
-   * Any subclass of Token that actually wants to return a non-null value can
-   * override this method as appropriate.
-   */
-  public Object getValue() {
-    return null;
-  }
-
-  /**
-   * No-argument constructor
-   */
-  public Token() {}
-
-  /**
-   * Constructs a new token for the specified Image.
-   */
-  public Token(int kind)
-  {
-    this(kind, null);
-  }
-
-  /**
-   * Constructs a new token for the specified Image and Kind.
-   */
-  public Token(int kind, String image)
-  {
-    this.kind = kind;
-    this.image = image;
-  }
-
-  /**
-   * Returns the image.
-   */
-  public String toString()
-  {
-    return image;
-  }
-
-  /**
-   * Returns a new Token object, by default. However, if you want, you
-   * can create and return subclass objects based on the value of ofKind.
-   * Simply add the cases to the switch for all those special cases.
-   * For example, if you have a subclass of Token called IDToken that
-   * you want to create if ofKind is ID, simply add something like :
-   *
-   *    case MyParserConstants.ID : return new IDToken(ofKind, image);
-   *
-   * to the following switch statement. Then you can cast matchedToken
-   * variable to the appropriate type and use sit in your lexical actions.
-   */
-  public static Token newToken(int ofKind, String image)
-  {
-    switch(ofKind)
-    {
-      default : return new Token(ofKind, image);
-    }
-  }
-
-  public static Token newToken(int ofKind)
-  {
-    return newToken(ofKind, null);
-  }
-
-}
-/* JavaCC - OriginalChecksum=2104130aa3f9189e35a4571dc4c8f0c9 (do not edit this line) */
diff --git a/java/org/apache/tomcat/util/http/parser/TokenMgrError.java b/java/org/apache/tomcat/util/http/parser/TokenMgrError.java
deleted file mode 100644
index b724438..0000000
--- a/java/org/apache/tomcat/util/http/parser/TokenMgrError.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
-/* JavaCCOptions: */
-package org.apache.tomcat.util.http.parser;
-
-/** Token Manager Error. */
- at SuppressWarnings("all") // Ignore warnings in generated code
-public class TokenMgrError extends Error
-{
-
-  /**
-   * The version identifier for this Serializable class.
-   * Increment only if the <i>serialized</i> form of the
-   * class changes.
-   */
-  private static final long serialVersionUID = 1L;
-
-  /*
-   * Ordinals for various reasons why an Error of this type can be thrown.
-   */
-
-  /**
-   * Lexical error occurred.
-   */
-  static final int LEXICAL_ERROR = 0;
-
-  /**
-   * An attempt was made to create a second instance of a static token manager.
-   */
-  static final int STATIC_LEXER_ERROR = 1;
-
-  /**
-   * Tried to change to an invalid lexical state.
-   */
-  static final int INVALID_LEXICAL_STATE = 2;
-
-  /**
-   * Detected (and bailed out of) an infinite loop in the token manager.
-   */
-  static final int LOOP_DETECTED = 3;
-
-  /**
-   * Indicates the reason why the exception is thrown. It will have
-   * one of the above 4 values.
-   */
-  int errorCode;
-
-  /**
-   * Replaces unprintable characters by their escaped (or unicode escaped)
-   * equivalents in the given string
-   */
-  protected static final String addEscapes(String str) {
-    StringBuffer retval = new StringBuffer();
-    char ch;
-    for (int i = 0; i < str.length(); i++) {
-      switch (str.charAt(i))
-      {
-        case 0 :
-          continue;
-        case '\b':
-          retval.append("\\b");
-          continue;
-        case '\t':
-          retval.append("\\t");
-          continue;
-        case '\n':
-          retval.append("\\n");
-          continue;
-        case '\f':
-          retval.append("\\f");
-          continue;
-        case '\r':
-          retval.append("\\r");
-          continue;
-        case '\"':
-          retval.append("\\\"");
-          continue;
-        case '\'':
-          retval.append("\\\'");
-          continue;
-        case '\\':
-          retval.append("\\\\");
-          continue;
-        default:
-          if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
-            String s = "0000" + Integer.toString(ch, 16);
-            retval.append("\\u" + s.substring(s.length() - 4, s.length()));
-          } else {
-            retval.append(ch);
-          }
-          continue;
-      }
-    }
-    return retval.toString();
-  }
-
-  /**
-   * Returns a detailed message for the Error when it is thrown by the
-   * token manager to indicate a lexical error.
-   * Parameters :
-   *    EOFSeen     : indicates if EOF caused the lexical error
-   *    curLexState : lexical state in which this error occurred
-   *    errorLine   : line number when the error occurred
-   *    errorColumn : column number when the error occurred
-   *    errorAfter  : prefix that was seen before this error occurred
-   *    curchar     : the offending character
-   * Note: You can customize the lexical error message by modifying this method.
-   */
-  protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
-    return("Lexical error at line " +
-          errorLine + ", column " +
-          errorColumn + ".  Encountered: " +
-          (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
-          "after : \"" + addEscapes(errorAfter) + "\"");
-  }
-
-  /**
-   * You can also modify the body of this method to customize your error messages.
-   * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
-   * of end-users concern, so you can return something like :
-   *
-   *     "Internal Error : Please file a bug report .... "
-   *
-   * from this method for such cases in the release version of your parser.
-   */
-  public String getMessage() {
-    return super.getMessage();
-  }
-
-  /*
-   * Constructors of various flavors follow.
-   */
-
-  /** No arg constructor. */
-  public TokenMgrError() {
-  }
-
-  /** Constructor with message and reason. */
-  public TokenMgrError(String message, int reason) {
-    super(message);
-    errorCode = reason;
-  }
-
-  /** Full Constructor. */
-  public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
-    this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
-  }
-}
-/* JavaCC - OriginalChecksum=c0e71cb84849413e4aa36c7471643b93 (do not edit this line) */
diff --git a/java/org/apache/tomcat/util/http/res/LocalStrings.properties b/java/org/apache/tomcat/util/http/res/LocalStrings.properties
index 33102df..67b00f0 100644
--- a/java/org/apache/tomcat/util/http/res/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/http/res/LocalStrings.properties
@@ -15,8 +15,13 @@
 
 # HttpMessages. The values in this file will be used in HTTP headers and as such
 # may only contain TEXT as defined by RFC 2616
+# All status codes registered with IANA can be found at
+# http://www.iana.org/assignments/http-status-codes/http-status-codes.xml
+# The list might be kept in sync with the one in
+# java/org/apache/catalina/valves/LocalStrings.properties
 sc.100=Continue
 sc.101=Switching Protocols
+sc.102=Processing
 sc.200=OK
 sc.201=Created
 sc.202=Accepted
@@ -25,13 +30,16 @@ sc.204=No Content
 sc.205=Reset Content
 sc.206=Partial Content
 sc.207=Multi-Status
+sc.208=Already Reported
+sc.226=IM Used
 sc.300=Multiple Choices
 sc.301=Moved Permanently
-sc.302=Moved Temporarily
+sc.302=Found
 sc.303=See Other
 sc.304=Not Modified
 sc.305=Use Proxy
 sc.307=Temporary Redirect
+sc.308=Permanent Redirect
 sc.400=Bad Request
 sc.401=Unauthorized
 sc.402=Payment Required
@@ -53,10 +61,18 @@ sc.417=Expectation Failed
 sc.422=Unprocessable Entity
 sc.423=Locked
 sc.424=Failed Dependency
+sc.426=Upgrade Required
+sc.428=Precondition Required
+sc.429=Too Many Requests
+sc.431=Request Header Fields Too Large
 sc.500=Internal Server Error
 sc.501=Not Implemented
 sc.502=Bad Gateway
 sc.503=Service Unavailable
 sc.504=Gateway Timeout
 sc.505=HTTP Version Not Supported
+sc.506=Variant Also Negotiates (Experimental)
 sc.507=Insufficient Storage
+sc.508=Loop Detected
+sc.510=Not Extended
+sc.511=Network Authentication Required
diff --git a/java/org/apache/tomcat/util/http/res/LocalStrings_ja.properties b/java/org/apache/tomcat/util/http/res/LocalStrings_ja.properties
index 99234bc..c65b618 100644
--- a/java/org/apache/tomcat/util/http/res/LocalStrings_ja.properties
+++ b/java/org/apache/tomcat/util/http/res/LocalStrings_ja.properties
@@ -14,50 +14,6 @@
 # limitations under the License.
 
 # HttpMessages. The values in this file will be used in HTTP headers and as such
-# may only contain TEXT as defined by RFC 2616. Since Japanese language messages
-# do not meet this requirement, English text is used.
-sc.100=Continue
-sc.101=Switching Protocols
-sc.200=OK
-sc.201=Created
-sc.202=Accepted
-sc.203=Non-Authoritative Information
-sc.204=No Content
-sc.205=Reset Content
-sc.206=Partial Content
-sc.207=Multi-Status
-sc.300=Multiple Choices
-sc.301=Moved Permanently
-sc.302=Moved Temporarily
-sc.303=See Other
-sc.304=Not Modified
-sc.305=Use Proxy
-sc.307=Temporary Redirect
-sc.400=Bad Request
-sc.401=Unauthorized
-sc.402=Payment Required
-sc.403=Forbidden
-sc.404=Not Found
-sc.405=Method Not Allowed
-sc.406=Not Acceptable
-sc.407=Proxy Authentication Required
-sc.408=Request Timeout
-sc.409=Conflict
-sc.410=Gone
-sc.411=Length Required
-sc.412=Precondition Failed
-sc.413=Request Entity Too Large
-sc.414=Request-URI Too Long
-sc.415=Unsupported Media Type
-sc.416=Requested Range Not Satisfiable
-sc.417=Expectation Failed
-sc.422=Unprocessable Entity
-sc.423=Locked
-sc.424=Failed Dependency
-sc.500=Internal Server Error
-sc.501=Not Implemented
-sc.502=Bad Gateway
-sc.503=Service Unavailable
-sc.504=Gateway Timeout
-sc.505=HTTP Version Not Supported
-sc.507=Insufficient Storage
+# may only contain TEXT as defined by RFC 2616. Since Japanese language
+# messages do not meet this requirement, English text is used.
+# The English messages can be found in the default file LocalStrings.properties.
diff --git a/java/org/apache/tomcat/util/net/AprEndpoint.java b/java/org/apache/tomcat/util/net/AprEndpoint.java
index 3ac6283..e9b4d3c 100644
--- a/java/org/apache/tomcat/util/net/AprEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AprEndpoint.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Executor;
 import java.util.concurrent.RejectedExecutionException;
 
 import org.apache.juli.logging.Log;
@@ -317,6 +318,15 @@ public class AprEndpoint extends AbstractEndpoint {
     public void setSSLInsecureRenegotiation(boolean SSLInsecureRenegotiation) { this.SSLInsecureRenegotiation = SSLInsecureRenegotiation; }
     public boolean getSSLInsecureRenegotiation() { return SSLInsecureRenegotiation; }
 
+    protected boolean SSLHonorCipherOrder = false;
+    /**
+     * Set to <code>true</code> to enforce the <i>server's</i> cipher order
+     * instead of the default which is to allow the client to choose a
+     * preferred cipher.
+     */
+    public void setSSLHonorCipherOrder(boolean SSLHonorCipherOrder) { this.SSLHonorCipherOrder = SSLHonorCipherOrder; }
+    public boolean getSSLHonorCipherOrder() { return SSLHonorCipherOrder; }
+
 
     /**
      * Port in use.
@@ -526,6 +536,24 @@ public class AprEndpoint extends AbstractEndpoint {
                                           SSL.versionString()));
                 }
             }
+
+            // Set cipher order: client (default) or server
+            if (SSLHonorCipherOrder) {
+                boolean orderCiphersSupported = false;
+                try {
+                    orderCiphersSupported = SSL.hasOp(SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+                    if (orderCiphersSupported)
+                        SSLContext.setOptions(sslContext, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+                } catch (UnsatisfiedLinkError e) {
+                    // Ignore
+                }
+                if (!orderCiphersSupported) {
+                    // OpenSSL does not support ciphers ordering.
+                    log.warn(sm.getString("endpoint.warn.noHonorCipherOrder",
+                                          SSL.versionString()));
+                }
+            }
+
             // List the ciphers that the client is permitted to negotiate
             SSLContext.setCipherSuite(sslContext, SSLCipherSuite);
             // Load Server key and certificate
@@ -815,9 +843,15 @@ public class AprEndpoint extends AbstractEndpoint {
      */
     protected boolean processSocket(long socket) {
         try {
-            SocketWrapper<Long> wrapper =
-                new SocketWrapper<Long>(Long.valueOf(socket));
-            getExecutor().execute(new SocketProcessor(wrapper, null));
+            Executor executor = getExecutor();
+            if (executor == null) {
+                log.warn(sm.getString("endpoint.warn.noExector",
+                        Long.valueOf(socket), null));
+            } else {
+                SocketWrapper<Long> wrapper =
+                    new SocketWrapper<Long>(Long.valueOf(socket));
+                executor.execute(new SocketProcessor(wrapper, null));
+            }
         } catch (RejectedExecutionException x) {
             log.warn("Socket processing request was rejected for:"+socket,x);
             return false;
@@ -835,11 +869,17 @@ public class AprEndpoint extends AbstractEndpoint {
     /**
      * Process given socket for an event.
      */
-    protected boolean processSocket(long socket, SocketStatus status) {
+    public boolean processSocket(long socket, SocketStatus status) {
         try {
-            SocketWrapper<Long> wrapper =
-                    new SocketWrapper<Long>(Long.valueOf(socket));
-            getExecutor().execute(new SocketEventProcessor(wrapper, status));
+            Executor executor = getExecutor();
+            if (executor == null) {
+                log.warn(sm.getString("endpoint.warn.noExector",
+                        Long.valueOf(socket), status));
+            } else {
+                SocketWrapper<Long> wrapper =
+                        new SocketWrapper<Long>(Long.valueOf(socket));
+                executor.execute(new SocketEventProcessor(wrapper, status));
+            }
         } catch (RejectedExecutionException x) {
             log.warn("Socket processing request was rejected for:"+socket,x);
             return false;
@@ -870,11 +910,14 @@ public class AprEndpoint extends AbstractEndpoint {
                             Thread.currentThread().setContextClassLoader(
                                     getClass().getClassLoader());
                         }
-                        // During shutdown, executor may be null - avoid NPE
-                        if (!running) {
+                        Executor executor = getExecutor();
+                        if (executor == null) {
+                            log.warn(sm.getString("endpoint.warn.noExector",
+                                    socket, status));
                             return false;
+                        } else {
+                            executor.execute(proc);
                         }
-                        getExecutor().execute(proc);
                     } finally {
                         if (Constants.IS_SECURITY_ENABLED) {
                             PrivilegedAction<Void> pa = new PrivilegedSetTccl(loader);
@@ -1067,6 +1110,9 @@ public class AprEndpoint extends AbstractEndpoint {
      */
     public class Poller extends Thread {
 
+        public static final int FLAGS_READ = Poll.APR_POLLIN;
+        public static final int FLAGS_WRITE  = Poll.APR_POLLOUT;
+
         // Need two pollsets since the socketTimeout and the keep-alive timeout
         // can have different values.
         private long connectionPollset = 0;
@@ -1075,6 +1121,7 @@ public class AprEndpoint extends AbstractEndpoint {
 
         private long[] addSocket;
         private int[] addSocketTimeout;
+        private int[] addSocketFlags;
 
         private volatile int addCount = 0;
 
@@ -1107,7 +1154,8 @@ public class AprEndpoint extends AbstractEndpoint {
             desc = new long[size * 2];
             keepAliveCount = 0;
             addSocket = new long[size];
-            addSocketTimeout= new int[size];
+            addSocketTimeout = new int[size];
+            addSocketFlags = new int[size];
             addCount = 0;
         }
 
@@ -1161,8 +1209,10 @@ public class AprEndpoint extends AbstractEndpoint {
          * @param socket    to add to the poller
          * @param timeout   read timeout (in milliseconds) to use with this
          *                  socket. Use -1 for infinite timeout
+         * @param flags     flags that define the events that are to be polled
+         *                  for
          */
-        public void add(long socket, int timeout) {
+        public void add(long socket, int timeout, int flags) {
             synchronized (this) {
                 // Add socket to the list. Newly added sockets will wait
                 // at most for pollTime before being polled
@@ -1177,6 +1227,7 @@ public class AprEndpoint extends AbstractEndpoint {
                 }
                 addSocket[addCount] = socket;
                 addSocketTimeout[addCount] = timeout;
+                addSocketFlags[addCount] = flags;
                 addCount++;
                 this.notify();
             }
@@ -1235,7 +1286,7 @@ public class AprEndpoint extends AbstractEndpoint {
                                     }
                                     int rv = Poll.addWithTimeout(
                                             connectionPollset, addSocket[i],
-                                            Poll.APR_POLLIN, timeout);
+                                            addSocketFlags[i], timeout);
                                     if (rv == Status.APR_SUCCESS) {
                                         successCount++;
                                     } else {
@@ -1618,7 +1669,8 @@ public class AprEndpoint extends AbstractEndpoint {
                                     // If all done put the socket back in the poller for
                                     // processing of further requests
                                     getPoller().add(state.socket,
-                                            getKeepAliveTimeout());
+                                            getKeepAliveTimeout(),
+                                            Poller.FLAGS_READ);
                                 } else {
                                     // Close the socket since this is
                                     // the end of not keep-alive request.
@@ -1710,7 +1762,7 @@ public class AprEndpoint extends AbstractEndpoint {
                 if (!deferAccept) {
                     if (setSocketOptions(socket.getSocket().longValue())) {
                         getPoller().add(socket.getSocket().longValue(),
-                                getSoTimeout());
+                                getSoTimeout(), Poller.FLAGS_READ);
                     } else {
                         // Close socket and pool
                         destroySocket(socket.getSocket().longValue());
diff --git a/java/org/apache/tomcat/util/net/SocketProperties.java b/java/org/apache/tomcat/util/net/SocketProperties.java
index 67fa19b..f937ff2 100644
--- a/java/org/apache/tomcat/util/net/SocketProperties.java
+++ b/java/org/apache/tomcat/util/net/SocketProperties.java
@@ -139,16 +139,6 @@ public class SocketProperties {
     protected Integer soTimeout = new Integer(20000);
 
     /**
-     * Traffic class option, value between 0 and 255
-     * IPTOS_LOWCOST (0x02)
-     * IPTOS_RELIABILITY (0x04)
-     * IPTOS_THROUGHPUT (0x08)
-     * IPTOS_LOWDELAY (0x10)
-     * JVM default used if not set
-     */
-    protected Integer soTrafficClass = null;
-
-    /**
      * Performance preferences according to
      * http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)
      * All three performance attributes must be set or the JVM defaults will be
@@ -207,8 +197,6 @@ public class SocketProperties {
             socket.setSoTimeout(soTimeout.intValue());
         if (tcpNoDelay != null)
             socket.setTcpNoDelay(tcpNoDelay.booleanValue());
-        if (soTrafficClass != null)
-            socket.setTrafficClass(soTrafficClass.intValue());
     }
 
     public void setProperties(ServerSocket socket) throws SocketException{
@@ -271,10 +259,6 @@ public class SocketProperties {
         return soTimeout.intValue();
     }
 
-    public int getSoTrafficClass() {
-        return soTrafficClass.intValue();
-    }
-
     public boolean getTcpNoDelay() {
         return tcpNoDelay.booleanValue();
     }
@@ -332,10 +316,6 @@ public class SocketProperties {
         this.tcpNoDelay = Boolean.valueOf(tcpNoDelay);
     }
 
-    public void setSoTrafficClass(int soTrafficClass) {
-        this.soTrafficClass = Integer.valueOf(soTrafficClass);
-    }
-
     public void setSoTimeout(int soTimeout) {
         this.soTimeout = Integer.valueOf(soTimeout);
     }
diff --git a/java/org/apache/tomcat/util/net/res/LocalStrings.properties b/java/org/apache/tomcat/util/net/res/LocalStrings.properties
index 045ff98..56d9038 100644
--- a/java/org/apache/tomcat/util/net/res/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/res/LocalStrings.properties
@@ -41,10 +41,13 @@ endpoint.process.fail=Error allocating socket processor
 endpoint.sendfile.error=Unexpected sendfile error
 endpoint.sendfile.addfail=Sendfile failure: [{0}] {1}
 endpoint.sendfile.nosupport=Disabling sendfile, since either the APR version or the system doesn't support it
-endpoint.warn.noInsecureReneg=Secure renegotation is not supported by the SSL library {0}
+endpoint.warn.noInsecureReneg=Secure re-negotiation is not supported by the SSL library {0}
+endpoint.warn.noHonorCipherOrder='Honor cipher order' option is not supported by the SSL library {0}
 endpoint.warn.unlockAcceptorFailed=Acceptor thread [{0}] failed to unlock. Forcing hard socket shutdown.
+endpoint.warn.noHonorCipherOrder='Honor cipher order' option is not supported by the SSL library {0}
 endpoint.debug.channelCloseFail=Failed to close channel
 endpoint.debug.socketCloseFail=Failed to close socket
 endpoint.apr.noSslCertFile=Connector attribute SSLCertificateFile must be defined when using SSL with APR
 endpoint.apr.invalidSslProtocol=An invalid value [{0}] was provided for the SSLProtocol attribute
 endpoint.nio.selectorCloseFail=Failed to close selector when closing the poller
+endpoint.warn.noExector=Failed to process socket [{0}] in state [{1}] because the executor had already been shutdown
diff --git a/modules/jdbc-pool/doc/jdbc-pool.xml b/modules/jdbc-pool/doc/jdbc-pool.xml
index ff108c2..bb497a2 100644
--- a/modules/jdbc-pool/doc/jdbc-pool.xml
+++ b/modules/jdbc-pool/doc/jdbc-pool.xml
@@ -617,6 +617,12 @@
            The default value is <code>true</code>.
         </p>
       </attribute>
+      <attribute name="objectName" required="false">
+        <p>(String) Define a valid <code>javax.management.ObjectName</code> string that will be used to register this object with the platform mbean server
+           The default value is <code>null</code> and the object will be registered using
+           tomcat.jdbc:type=org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx,name=the-name-of-the-pool
+        </p>
+      </attribute>
     </attributes>
   </subsection>
   <subsection name="org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer">
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 c0d0c79..a95f6a5 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
@@ -54,10 +54,15 @@ import org.apache.juli.logging.LogFactory;
  */
 
 public class ConnectionPool {
+
+    /**
+     * Default domain for objects registering with an mbean server
+     */
+    public static final String POOL_JMX_DOMAIN = "tomcat.jdbc";
     /**
      * Prefix type for JMX registration
      */
-    public static final String POOL_JMX_TYPE_PREFIX = "tomcat.jdbc:type=";
+    public static final String POOL_JMX_TYPE_PREFIX = POOL_JMX_DOMAIN+":type=";
 
     /**
      * Logger
@@ -829,7 +834,7 @@ public class ConnectionPool {
      */
     protected boolean terminateTransaction(PooledConnection con) {
         try {
-            if (con.getPoolProperties().getDefaultAutoCommit()==Boolean.FALSE) {
+            if (Boolean.FALSE.equals(con.getPoolProperties().getDefaultAutoCommit())) {
                 if (this.getPoolProperties().getRollbackOnReturn()) {
                     boolean autocommit = con.getConnection().getAutoCommit();
                     if (!autocommit) con.getConnection().rollback();
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSource.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSource.java
index 8e05077..b499d6e 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSource.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DataSource.java
@@ -113,12 +113,14 @@ public class DataSource extends DataSourceProxy implements javax.sql.DataSource,
      * @throws MalformedObjectNameException
      */
     public ObjectName createObjectName(ObjectName original) throws MalformedObjectNameException {
-        String domain = "tomcat.jdbc";
+        String domain = ConnectionPool.POOL_JMX_DOMAIN;
         Hashtable<String,String> properties = original.getKeyPropertyList();
         String origDomain = original.getDomain();
         properties.put("type", "ConnectionPool");
         properties.put("class", this.getClass().getName());
-        if (original.getKeyProperty("path")!=null) {
+        if (original.getKeyProperty("path")!=null || properties.get("context")!=null) {
+            //this ensures that if the registration came from tomcat, we're not losing
+            //the unique domain, but putting that into as an engine attribute
             properties.put("engine", origDomain);
         }
         ObjectName name = new ObjectName(domain,properties);
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DisposableConnectionFacade.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DisposableConnectionFacade.java
index e93f4b6..5d88b93 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DisposableConnectionFacade.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/DisposableConnectionFacade.java
@@ -17,6 +17,7 @@
 package org.apache.tomcat.jdbc.pool;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.sql.SQLException;
 
 /**
@@ -44,10 +45,26 @@ public class DisposableConnectionFacade extends JdbcInterceptor {
     public void reset(ConnectionPool parent, PooledConnection con) {
     }
 
+
+
+    @Override
+    public int hashCode() {
+        return System.identityHashCode(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return this==obj;
+    }
+
     @Override
     public Object invoke(Object proxy, Method method, Object[] args)
             throws Throwable {
-        if (getNext()==null) {
+        if (compare(EQUALS_VAL, method)) {
+            return this.equals(Proxy.getInvocationHandler(args[0]));
+        } else if (compare(HASHCODE_VAL, method)) {
+            return this.hashCode();
+        } else if (getNext()==null) {
             if (compare(ISCLOSED_VAL, method)) {
                 return Boolean.TRUE;
             }
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
index 3ed8544..00b8056 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
@@ -67,6 +67,16 @@ public abstract class JdbcInterceptor implements InvocationHandler {
     public static final String ISVALID_VAL = "isValid";
 
     /**
+     * {@link java.lang.Object#equals(Object)}
+     */
+    public static final String EQUALS_VAL = "equals";
+
+    /**
+     * {@link java.lang.Object#hashCode()}
+     */
+    public static final String HASHCODE_VAL = "hashCode";
+
+    /**
      * Properties for this interceptor.
      */
     protected Map<String,InterceptorProperty> properties = null;
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
index 498ca54..b9a1cd5 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
@@ -796,7 +796,7 @@ public interface PoolConfiguration {
     /**
      * Set to true if you want the connection pool to commit any pending transaction when a connection is returned.
      * The default value is false, as this could result in committing data.
-     * This parameter is only looked at if the {@link java.sql.Connection#getAutoCommit()} returns false
+     * This parameter is only looked at if the {@link #getDefaultAutoCommit()} returns false
      * @param commitOnReturn set to true if the pool should call {@link java.sql.Connection#commit()} when a connection is returned to the pool.
      * Default is false
      */
@@ -810,7 +810,7 @@ public interface PoolConfiguration {
     /**
      * Set to true if you want the connection pool to rollback any pending transaction when a connection is returned.
      * The default value is false, as this could result in committing data.
-     * This parameter is only looked at if the {@link java.sql.Connection#getAutoCommit()} returns false
+     * This parameter is only looked at if the {@link #getDefaultAutoCommit()} returns false
      * @param rollbackOnReturn set to true if the pool should call {@link java.sql.Connection#rollback()} when a connection is returned to the pool.
      * Default is false
      */
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
index b4ca97f..becd283 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.io.Serializable;
 import java.lang.reflect.Method;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -805,7 +806,7 @@ public class PoolProperties implements PoolConfiguration, Cloneable, Serializabl
                 final String[] prefix = new String[] {"get","is"};
                 for (int j=0; j<prefix.length; j++) {
 
-                    String name = prefix[j] + fields[i].substring(0, 1).toUpperCase() +
+                    String name = prefix[j] + fields[i].substring(0, 1).toUpperCase(Locale.US) +
                                   fields[i].substring(1);
                     Method m = null;
                     try {
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 3fed29d..f49fca8 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
@@ -183,7 +183,8 @@ public class PooledConnection {
         }
 
         //set up the default state, unless we expect the interceptor to do it
-        if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0) {
+        if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0 ||
+                poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getSimpleName())<0) {
             if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
             if (poolProperties.getDefaultReadOnly()!=null) connection.setReadOnly(poolProperties.getDefaultReadOnly().booleanValue());
             if (poolProperties.getDefaultAutoCommit()!=null) connection.setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue());
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java
index 6b25f01..1e15e8c 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java
@@ -58,6 +58,8 @@ public class SlowQueryReportJmx extends SlowQueryReport implements NotificationE
     public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY";
     public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY";
 
+    public static final String objectNameAttribute = "objectName";
+
     protected static CompositeType SLOW_QUERY_TYPE;
 
     private static final Log log = LogFactory.getLog(SlowQueryReportJmx.class);
@@ -267,8 +269,13 @@ public class SlowQueryReportJmx extends SlowQueryReport implements NotificationE
     }
 
 
-    public static ObjectName getObjectName(Class<?> clazz, String poolName) throws MalformedObjectNameException {
-        ObjectName oname = new ObjectName(ConnectionPool.POOL_JMX_TYPE_PREFIX+clazz.getName()+",name=" + poolName);
+    public ObjectName getObjectName(Class<?> clazz, String poolName) throws MalformedObjectNameException {
+        ObjectName oname = null;
+        if (getProperties().containsKey(objectNameAttribute)) {
+            oname = new ObjectName(getProperties().get(objectNameAttribute).getValue());
+        } else {
+            oname = new ObjectName(ConnectionPool.POOL_JMX_TYPE_PREFIX+clazz.getName()+",name=" + poolName);
+        }
         return oname;
     }
 
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/EqualsHashCodeTest.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/EqualsHashCodeTest.java
new file mode 100644
index 0000000..0aecc3b
--- /dev/null
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/EqualsHashCodeTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.tomcat.jdbc.test;
+
+import java.sql.Connection;
+
+import javax.sql.PooledConnection;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.test.driver.Driver;
+
+public class EqualsHashCodeTest extends DefaultTestCase{
+    public static final String password = "password";
+    public static final String username = "username";
+
+    public EqualsHashCodeTest(String s) {
+        super(s);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        this.datasource.setDriverClassName(Driver.class.getName());
+        this.datasource.setUrl("jdbc:tomcat:test");
+        this.datasource.setPassword(password);
+        this.datasource.setMaxActive(1);
+        this.datasource.setMinIdle(datasource.getMaxActive());
+        this.datasource.setMaxIdle(datasource.getMaxActive());
+        this.datasource.setUsername(username);
+        this.datasource.getConnection().close();
+        ConnectionPool pool = datasource.createPool();
+    }
+
+    public void testEquals() throws Exception {
+        Connection con1 = datasource.getConnection();
+        Connection real1 = ((PooledConnection)con1).getConnection();
+        assertEquals(con1, con1);
+        con1.close();
+        assertEquals(con1, con1);
+        Connection con2 = datasource.getConnection();
+        Connection real2 = ((PooledConnection)con2).getConnection();
+        assertEquals(real1,real2);
+        assertEquals(con2, con2);
+        assertNotSame(con1, con2);
+        con2.close();
+        assertEquals(con2, con2);
+    }
+
+    public void testHashCode() throws Exception {
+        Connection con1 = datasource.getConnection();
+        assertEquals(con1.hashCode(), con1.hashCode());
+        con1.close();
+        assertEquals(con1.hashCode(), con1.hashCode());
+        Connection con2 = datasource.getConnection();
+        assertEquals(con2.hashCode(), con2.hashCode());
+        assertNotSame(con1.hashCode(), con2.hashCode());
+        con2.close();
+        assertEquals(con2.hashCode(), con2.hashCode());
+    }
+}
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 5364c17..e661f44 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
@@ -102,7 +102,7 @@ public class TestSlowQueryReport extends DefaultTestCase {
         ClientListener listener = new ClientListener();
         ConnectionPool pool = datasource.getPool();
         ManagementFactory.getPlatformMBeanServer().addNotificationListener(
-                SlowQueryReportJmx.getObjectName(SlowQueryReportJmx.class, pool.getName()),
+                new SlowQueryReportJmx().getObjectName(SlowQueryReportJmx.class, pool.getName()),
                 listener,
                 null,
                 null);
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 1e9a6b4..1f8301e 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
@@ -32,6 +32,7 @@ import java.sql.Statement;
 import java.sql.Struct;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.Executor;
 
 import org.apache.tomcat.jdbc.pool.PooledConnection;
 
@@ -284,4 +285,25 @@ public class Connection implements java.sql.Connection {
         return null;
     }
 
+    // ---------------------------------------------------------- Java 7 methods
+    // Can't add @Override annotations since this code also has to compile with
+    // Java 6 for Tomcat 7.
+
+    public void setSchema(String schema) throws SQLException {
+    }
+
+    public String getSchema() throws SQLException {
+        return null;
+    }
+
+    public void abort(Executor executor) throws SQLException {
+    }
+
+    public void setNetworkTimeout(Executor executor, int milliseconds)
+            throws SQLException {
+    }
+
+    public int getNetworkTimeout() throws SQLException {
+        return 0;
+    }
 }
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 2c0b85b..38e9db3 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
@@ -20,8 +20,10 @@ import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.DriverPropertyInfo;
 import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Logger;
 
 public class Driver implements java.sql.Driver {
     public static final String url = "jdbc:tomcat:test";
@@ -75,4 +77,12 @@ public class Driver implements java.sql.Driver {
     public boolean jdbcCompliant() {
         return false;
     }
+
+    // ---------------------------------------------------------- Java 7 methods
+    // Can't add @Override annotations since this code also has to compile with
+    // Java 6 for Tomcat 7.
+
+    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+        return null;
+    }
 }
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 68e5b39..d535723 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
@@ -1208,4 +1208,16 @@ public class ResultSet implements java.sql.ResultSet {
         return null;
     }
 
+    // ---------------------------------------------------------- Java 7 methods
+    // Can't add @Override annotations since this code also has to compile with
+    // Java 6 for Tomcat 7.
+
+    public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
+        return null;
+    }
+
+    public <T> T getObject(String columnLabel, Class<T> type)
+            throws SQLException {
+        return null;
+    }
 }
diff --git a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Statement.java b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Statement.java
index 4f7254a..8040613 100644
--- a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Statement.java
+++ b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/test/driver/Statement.java
@@ -1291,4 +1291,24 @@ public class Statement implements CallableStatement {
         return null;
     }
 
+    // ---------------------------------------------------------- Java 7 methods
+    // Can't add @Override annotations since this code also has to compile with
+    // Java 6 for Tomcat 7.
+
+    public void closeOnCompletion() throws SQLException {
+    }
+
+    public boolean isCloseOnCompletion() throws SQLException {
+        return false;
+    }
+
+    public <T> T getObject(int parameterIndex, Class<T> type)
+            throws SQLException {
+        return null;
+    }
+
+    public <T> T getObject(String parameterName, Class<T> type)
+            throws SQLException {
+        return null;
+    }
 }
diff --git a/res/maven/README.txt b/res/maven/README.txt
index 76fb42c..a31fe9f 100644
--- a/res/maven/README.txt
+++ b/res/maven/README.txt
@@ -15,12 +15,27 @@
   limitations under the License.
 ================================================================================
 
-$Id: README.txt 1234158 2012-01-20 21:44:13Z markt $
+$Id: README.txt 1350902 2012-06-16 10:10:40Z kkolinko $
+
+General preparations before any publishing:
+1 - Download Maven Ant Tasks (version 2.1.0 is known to work) and place it in
+    this directory
+2 - Generate a standard Tomcat release (ant release)
+3 - Copy mvn.properties.default to mvn.properties and adjust it as necessary.
+    You will need to set asf.ldap.username and you'll probably need to set
+    gpg.exec
+    The other properties should be OK. Note: you will be prompted for your
+    GPG pass-phrase and LDAP password when the script runs.
+
+To publish a snapshot do the following:
+1 - ant -f mvn-pub.xml deploy-snapshot
+    This populates
+    https://repository.apache.org/content/repositories/snapshots/org/apache/tomcat/
 
 To release do the following:
-1 - copy mvn.properties.default to mvn.properties and adjust it.
-2 - ant -f mvn-pub.xml deploy-release
-    that step creates a staging in https://repository.apache.org/index.html#stagingRepositories
-3 - check the upload and then close the repository
-4 - include the repository in the VOTE thread
-5 - in https://repository.apache.org/index.html#stagingRepositories release it
+1 - ant -f mvn-pub.xml deploy-release
+    that step creates a staging area in
+    https://repository.apache.org/index.html#stagingRepositories
+2 - check the upload and then close the repository
+3 - include the repository in the VOTE thread
+4 - in https://repository.apache.org/index.html#stagingRepositories release it
diff --git a/res/maven/mvn-pub.xml b/res/maven/mvn-pub.xml
index 79d1c5b..13fca90 100644
--- a/res/maven/mvn-pub.xml
+++ b/res/maven/mvn-pub.xml
@@ -15,74 +15,32 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-<project name="Tomcat 7.0 Maven Deployment" default="" basedir="." xmlns:artifact="urn:maven-artifact-ant">
+<project name="Tomcat 7.0 Maven Deployment" default="" basedir="."
+         xmlns:artifact="urn:maven-artifact-ant">
   <!--
-    Built for using Maven Ant Tasks 2.0.10 - download to this directory
-    You'll also need to install jsch 0.1.42 and manually configure
-    wagon-ssh 1.0-beta-2 to use the updated jsch. This will also add a
-    requirement for jzlib 1.0.7
-  -->
-  <!--
-  Properties required to be set:
-  maven.repo.url - the URL of the repository, for example scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository
-  maven.repo.repositoryId - the id of the repository, for example apache.snapshots
-  maven.deploy.version - the version that the components will be deployed as, for example @MAVEN.DEPLOY.VERSION@
-  tomcat.lib.path - the path to tomcat JAR files
-  tomcat.bin.path - the path to tomcat's bin directory (for other JAR files)
-  tomcat.pom.path - the path to the POM files
-
-  For passwordless upload you'll also need to set
-  maven.username        - YOUR APACHE LDAP USERNAME (ASF ID normally).
-  maven.password        - YOUR APACHE LDAP PASSWORD
-  maven.scp.username    - Your ASF ID
-  maven.scp.privateKey  - Path to your exported ssh key
-
-  All these can be defined by mvn.properties (and defaults are in mvn.properties.default)
-
-  To get a private key to work on Windows, I followed these steps
-  1. on a linux box execute 'ssh-keygen -t rsa'
-  2. same linux box execute 'cat id_rsa.pub >> authorized_keys' and 'cat id_rsa.pub >> authorized_keys2'
-  3. Copy id_rsa and id_rsa.pub to my windows box
-  4. Import id_rsa into puttygen
-  5. export id_rsa from puttygen to OpenSSH key
-  6. The key you exported from puttygen is the one you reference from the <privateKey> element
-  7. Manually create the %USERPROFILE%\.ssh directory
-  8. Manually add the %USERPROFILE%\.ssh\known_hosts file with the entry for the host
+    Built for using Maven Ant Tasks (version 2.1.0 is known to work)
   -->
+
   <property file="${basedir}/mvn.properties"/>
   <property file="${basedir}/mvn.properties.default"/>
   <property name="local.repo" value="${user.home}/.m2/repository"/>
 
   <target name="init-maven">
-    <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant">
+    <typedef resource="org/apache/maven/artifact/ant/antlib.xml"
+             uri="urn:maven-artifact-ant">
       <classpath>
-        <pathelement location="${basedir}/maven-ant-tasks-2.0.10.jar" />
+        <pathelement location="${basedir}/maven-ant-tasks-2.1.0.jar" />
       </classpath>
     </typedef>
-    <artifact:install-provider artifactId="wagon-ssh" version="1.0-beta-2"/>
-  </target>
-
-  <target name="maven-deploy-nexus" depends="init-maven" if="nexus.set">
-    <!--deploy it in nexus -->
-    <artifact:deploy file="${file}">
-        <pom file="${pom}.tmp"/>
-        <remoteRepository url="${maven.repo.url}" layout="default">
-          <authentication username="${maven.username}" password="${maven.password}"/>
-        </remoteRepository>
-        <attach file="${file}.asc" type="jar.asc"/>
-        <attach file="${src}" classifier="sources" type="jar"/>
-        <attach file="${src}.asc" classifier="sources" type="jar.asc"/>
-        <attach file="${pom}.asc" type="pom.asc"/>
-    </artifact:deploy>
   </target>
 
-  <target name="maven-deploy-other" depends="init-maven" unless="nexus.set">
+  <target name="maven-deploy-nexus" depends="init-maven">
     <!--deploy it in nexus -->
     <artifact:deploy file="${file}">
         <pom file="${pom}.tmp"/>
         <remoteRepository url="${maven.repo.url}" layout="default">
-          <authentication username="${maven.scp.username}" privateKey="${maven.scp.privateKey}" passphrase="${maven.scp.passphrase}"/>
-          <authentication username="${maven.username}" password="${maven.password}"/>
+          <authentication username="${asf.ldap.username}"
+                          password="${asf.ldap.password}"/>
         </remoteRepository>
         <attach file="${file}.asc" type="jar.asc"/>
         <attach file="${src}" classifier="sources" type="jar"/>
@@ -106,21 +64,24 @@
     </copy>
 
     <!--sign the jar, the source and the pom -->
-    <exec executable="${maven.gpg.exec}" failonerror="true" inputstring="${maven.gpg.passphrase}">
+    <exec executable="${gpg.exec}" failonerror="true"
+          inputstring="${gpg.passphrase}">
       <arg value="--passphrase-fd"/>
       <arg value="0"/>
       <arg value="-a"/>
       <arg value="-b"/>
       <arg value="${file}"/>
     </exec>
-    <exec executable="${maven.gpg.exec}" failonerror="true" inputstring="${maven.gpg.passphrase}">
+    <exec executable="${gpg.exec}" failonerror="true"
+          inputstring="${gpg.passphrase}">
       <arg value="--passphrase-fd"/>
       <arg value="0"/>
       <arg value="-a"/>
       <arg value="-b"/>
       <arg value="${src}"/>
     </exec>
-    <exec executable="${maven.gpg.exec}" failonerror="true" inputstring="${maven.gpg.passphrase}">
+    <exec executable="${gpg.exec}" failonerror="true"
+          inputstring="${gpg.passphrase}">
       <arg value="--passphrase-fd"/>
       <arg value="0"/>
       <arg value="-a"/>
@@ -136,11 +97,6 @@
         <param name="pom" value="${pom}"/>
         <param name="src" value="${src}"/>
     </antcall>
-    <antcall target="maven-deploy-other">
-        <param name="file" value="${file}"/>
-        <param name="pom" value="${pom}"/>
-        <param name="src" value="${src}"/>
-    </antcall>
 
     <delete file="${pom}.tmp"/>
     <delete file="${pom}.asc"/>
@@ -182,14 +138,16 @@
     </copy>
 
     <!--sign the jar and pom -->
-    <exec executable="${maven.gpg.exec}" failonerror="true" inputstring="${maven.gpg.passphrase}">
+    <exec executable="${gpg.exec}" failonerror="true"
+          inputstring="${gpg.passphrase}">
       <arg value="--passphrase-fd"/>
       <arg value="0"/>
       <arg value="-a"/>
       <arg value="-b"/>
       <arg value="${file}"/>
     </exec>
-    <exec executable="${maven.gpg.exec}" failonerror="true" inputstring="${maven.gpg.passphrase}">
+    <exec executable="${gpg.exec}" failonerror="true"
+          inputstring="${gpg.passphrase}">
       <arg value="--passphrase-fd"/>
       <arg value="0"/>
       <arg value="-a"/>
@@ -202,8 +160,9 @@
     <!--deploy it-->
     <artifact:deploy file="${file}">
       <pom file="${pom}.tmp"/>
-      <remoteRepository url="${maven.repo.url}" layout="default">
-        <authentication username="${maven.scp.username}" privateKey="${maven.scp.privateKey}" passphrase="${maven.scp.passphrase}"/>
+      <remoteRepository url="${maven.repo.url}" layout="default" >
+        <authentication username="${asf.ldap.username}"
+                        password="${asf.ldap.password}"/>
       </remoteRepository>
       <attach file="${file}.asc" type="jar.asc"/>
       <attach file="${pom}.asc" type="pom.asc"/>
@@ -230,7 +189,7 @@
     </sequential>
   </macrodef>
 
-  <target name="generic-deploy" depends="init-maven">
+  <target name="generic-deploy" depends="init-maven,init-gpg,init-ldap">
     <!-- Standard jars in bin directory -->
     <!-- Skip bootstrap.jar - it is just a subset of catalina.jar -->
     <doMavenDeploy artifactId="tomcat-juli"
@@ -261,7 +220,6 @@
                   jarFileName="tomcat-jdbc.jar"
                srcJarFileName="tomcat-jdbc-src.jar"/>
 
-
     <doMavenDeploy artifactId="tomcat-el-api"
                   jarFileName="el-api.jar"
                srcJarFileName="el-api-src.jar"/>
@@ -335,31 +293,34 @@
 
   <target name="deploy-snapshot">
     <antcall target="generic-deploy">
-      <param name="maven.repo.repositoryId" value="${maven.snapshot.repo.repositoryId}"/>
+      <param name="maven.repo.repositoryId"
+             value="${maven.snapshot.repo.repositoryId}"/>
       <param name="maven.repo.url" value="${maven.snapshot.repo.url}"/>
       <param name="maven.deploy.version" value="7.0-SNAPSHOT"/>
     </antcall>
   </target>
 
-  <target name="deploy-staging">
-    <antcall target="generic-deploy">
-      <param name="maven.repo.repositoryId" value="${maven.release.repo.repositoryId}"/>
-      <param name="maven.repo.url" value="${maven.release.repo.url}"/>
-      <param name="maven.deploy.version" value="${maven.release.deploy.version}"/>
-    </antcall>
-  </target>
-
   <target name="deploy-release">
-    <property name="nexus.set" value="true"/>
     <antcall target="generic-deploy">
-      <param name="maven.repo.repositoryId" value="${maven.asf.release.repo.repositoryId}"/>
+      <param name="maven.repo.repositoryId"
+             value="${maven.asf.release.repo.repositoryId}"/>
       <param name="maven.repo.url" value="${maven.asf.release.repo.url}"/>
-      <param name="maven.deploy.version" value="${maven.asf.release.deploy.version}"/>
+      <param name="maven.deploy.version"
+             value="${maven.asf.release.deploy.version}"/>
     </antcall>
   </target>
 
-  <target name="help">
-    <echo>Help is on the way!</echo>
+  <target name="init-gpg">
+    <input message="Enter GPG pass-phrase" addproperty="gpg.passphrase" >
+      <handler type="secure"/>
+    </input>
+  </target>
+
+  <target name="init-ldap">
+    <input message="Enter ASF LDAP (same svn) password"
+           addproperty="asf.ldap.password" >
+      <handler type="secure"/>
+    </input>
   </target>
 
 </project>
diff --git a/res/maven/mvn.properties.default b/res/maven/mvn.properties.default
index ce68c40..b28c454 100644
--- a/res/maven/mvn.properties.default
+++ b/res/maven/mvn.properties.default
@@ -19,29 +19,23 @@
 # no need to change this file
 #
 
-#Maven properties
-maven.username=<!-- YOUR APACHE LDAP USERNAME -->
-maven.password=<!-- YOUR APACHE LDAP PASSWORD -->
-maven.scp.username=fhanik
-maven.scp.privateKey=${user.home}/.ssh/id_rsa.export
-maven.scp.passphrase=
-maven.gpg.exec=C:/software/GNU/GnuPG/gpg.exe
-maven.gpg.passphrase=*****
+# Authentication
+# Note: You will be prompted for your GPG passphrase and LDAP password when
+#        running this script
+asf.ldap.username=<!-- YOUR APACHE LDAP USERNAME -->
+gpg.exec=C:/software/GNU/GnuPG/gpg.exe
 
-#Maven snapshot properties
-maven.snapshot.repo.url=scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository
+# ASF Snapshot Repository (hosted on Nexus)
+maven.snapshot.repo.url=https://repository.apache.org/content/repositories/snapshots
 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.28
-
-#Maven release properties for the main ASF repo (staging in nexus)
+# ASF Release Repository (hosted on Nexus)
+# Note: Also used for staging releases prior to voting
 maven.asf.release.repo.url=https://repository.apache.org/service/local/staging/deploy/maven2
 maven.asf.release.repo.repositoryId=apache.releases
-maven.asf.release.deploy.version=7.0.28
 
+# Release version info
+maven.asf.release.deploy.version=7.0.33
 
 #Where do we load the libraries from
 tomcat.lib.path=../../output/build/lib
diff --git a/test/javax/el/TestBeanELResolver.java b/test/javax/el/TestBeanELResolver.java
new file mode 100644
index 0000000..3459e6f
--- /dev/null
+++ b/test/javax/el/TestBeanELResolver.java
@@ -0,0 +1,64 @@
+/*
+ * 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 junit.framework.Assert;
+
+import org.junit.Test;
+
+import org.apache.jasper.el.ELContextImpl;
+
+public class TestBeanELResolver {
+
+    @Test
+    public void testBug53421() {
+        ExpressionFactory factory = ExpressionFactory.newInstance();
+        ELContext context = new ELContextImpl();
+
+        Bean bean = new Bean();
+
+        ValueExpression varBean =
+            factory.createValueExpression(bean, Bean.class);
+        context.getVariableMapper().setVariable("bean", varBean);
+
+
+        ValueExpression ve = factory.createValueExpression(
+                context, "${bean.valueA}", String.class);
+        Exception e = null;
+        try {
+            ve.getValue(context);
+        } catch (PropertyNotFoundException pnfe) {
+            e = pnfe;
+        }
+        Assert.assertTrue("Wrong exception type",
+                e instanceof PropertyNotFoundException);
+        String type = Bean.class.getName();
+        @SuppressWarnings("null") // Assert above prevents msg being null
+        String msg = e.getMessage();
+        Assert.assertTrue("No reference to type [" + type +
+                "] where property cannot be found in [" + msg + "]",
+                msg.contains(type));
+    }
+
+    private static class Bean {
+
+        @SuppressWarnings("unused")
+        public void setValueA(String valueA) {
+            // NOOP
+        }
+    }
+}
diff --git a/test/javax/servlet/http/TestHttpServlet.java b/test/javax/servlet/http/TestHttpServlet.java
new file mode 100644
index 0000000..3777266
--- /dev/null
+++ b/test/javax/servlet/http/TestHttpServlet.java
@@ -0,0 +1,73 @@
+/*
+ * 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.servlet.http;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+public class TestHttpServlet extends TomcatBaseTest {
+
+    @Test
+    public void testBug53454() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        // Must have a real docBase - just use temp
+        StandardContext ctx = (StandardContext)
+            tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+
+        // Map the test Servlet
+        LargeBodyServlet largeBodyServlet = new LargeBodyServlet();
+        Tomcat.addServlet(ctx, "largeBodyServlet", largeBodyServlet);
+        ctx.addServletMapping("/", "largeBodyServlet");
+
+        tomcat.start();
+
+        Map<String,List<String>> resHeaders=
+                new HashMap<String, List<String>>();
+        int rc = headUrl("http://localhost:" + getPort() + "/", new ByteChunk(),
+               resHeaders);
+
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+        Assert.assertEquals(LargeBodyServlet.RESPONSE_LENGTH,
+                resHeaders.get("Content-Length").get(0));
+    }
+
+
+    private static class LargeBodyServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+        private static final String RESPONSE_LENGTH = "12345678901";
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            resp.setHeader("content-length", RESPONSE_LENGTH);
+        }
+    }
+}
diff --git a/test/org/apache/catalina/authenticator/TestDigestAuthenticator.java b/test/org/apache/catalina/authenticator/TestDigestAuthenticator.java
index d1b69b7..f741dc9 100644
--- a/test/org/apache/catalina/authenticator/TestDigestAuthenticator.java
+++ b/test/org/apache/catalina/authenticator/TestDigestAuthenticator.java
@@ -16,8 +16,6 @@
  */
 package org.apache.catalina.authenticator;
 
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -36,6 +34,7 @@ import org.apache.catalina.startup.TestTomcat.MapRealm;
 import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.catalina.util.ConcurrentMessageDigest;
 import org.apache.catalina.util.MD5Encoder;
 import org.apache.tomcat.util.buf.ByteChunk;
 
@@ -310,7 +309,7 @@ public class TestDigestAuthenticator extends TomcatBaseTest {
      */
     private static String buildDigestResponse(String user, String pwd,
             String uri, String realm, String nonce, String opaque, String nc,
-            String cnonce, String qop) throws NoSuchAlgorithmException {
+            String cnonce, String qop) {
 
         String a1 = user + ":" + realm + ":" + pwd;
         String a2 = "GET:" + uri;
@@ -343,14 +342,13 @@ public class TestDigestAuthenticator extends TomcatBaseTest {
         auth.append(md5response);
         auth.append("\"");
         if (qop != null) {
-            auth.append(", qop=\"");
+            auth.append(", qop=");
             auth.append(qop);
-            auth.append("\"");
+            auth.append("");
         }
         if (nc != null) {
-            auth.append(", nc=\"");
+            auth.append(", nc=");
             auth.append(nc);
-            auth.append("\"");
         }
         if (cnonce != null) {
             auth.append(", cnonce=\"");
@@ -361,12 +359,8 @@ public class TestDigestAuthenticator extends TomcatBaseTest {
         return auth.toString();
     }
 
-    private static String digest(String input) throws NoSuchAlgorithmException {
-        // This is slow but should be OK as this is only a test
-        MessageDigest md5 = MessageDigest.getInstance("MD5");
-        MD5Encoder encoder = new MD5Encoder();
-
-        md5.update(input.getBytes());
-        return encoder.encode(md5.digest());
+    private static String digest(String input) {
+        return MD5Encoder.encode(
+                ConcurrentMessageDigest.digestMD5(input.getBytes()));
     }
 }
diff --git a/test/org/apache/catalina/authenticator/TestSSOnonLoginAndDigestAuthenticator.java b/test/org/apache/catalina/authenticator/TestSSOnonLoginAndDigestAuthenticator.java
index 010baa1..939dac3 100644
--- a/test/org/apache/catalina/authenticator/TestSSOnonLoginAndDigestAuthenticator.java
+++ b/test/org/apache/catalina/authenticator/TestSSOnonLoginAndDigestAuthenticator.java
@@ -16,9 +16,6 @@
  */
 package org.apache.catalina.authenticator;
 
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -36,6 +33,7 @@ import org.apache.catalina.deploy.SecurityConstraint;
 import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.catalina.util.ConcurrentMessageDigest;
 import org.apache.catalina.util.MD5Encoder;
 import org.apache.tomcat.util.buf.ByteChunk;
 
@@ -418,7 +416,7 @@ public class TestSSOnonLoginAndDigestAuthenticator extends TomcatBaseTest {
      */
     private static String buildDigestResponse(String user, String pwd,
             String uri, String realm, String nonce, String opaque, String nc,
-            String cnonce, String qop) throws NoSuchAlgorithmException {
+            String cnonce, String qop) {
 
         String a1 = user + ":" + realm + ":" + pwd;
         String a2 = "GET:" + uri;
@@ -451,14 +449,12 @@ public class TestSSOnonLoginAndDigestAuthenticator extends TomcatBaseTest {
         auth.append(md5response);
         auth.append("\"");
         if (qop != null) {
-            auth.append(", qop=\"");
+            auth.append(", qop=");
             auth.append(qop);
-            auth.append("\"");
         }
         if (nc != null) {
-            auth.append(", nc=\"");
+            auth.append(", nc=");
             auth.append(nc);
-            auth.append("\"");
         }
         if (cnonce != null) {
             auth.append(", cnonce=\"");
@@ -469,13 +465,9 @@ public class TestSSOnonLoginAndDigestAuthenticator extends TomcatBaseTest {
         return auth.toString();
     }
 
-    private static String digest(String input) throws NoSuchAlgorithmException {
-        // This is slow but should be OK as this is only a test
-        MessageDigest md5 = MessageDigest.getInstance("MD5");
-        MD5Encoder encoder = new MD5Encoder();
-
-        md5.update(input.getBytes());
-        return encoder.encode(md5.digest());
+    private static String digest(String input) {
+        return MD5Encoder.encode(
+                ConcurrentMessageDigest.digestMD5(input.getBytes()));
     }
 
     /*
diff --git a/test/org/apache/catalina/authenticator/TesterDigestAuthenticatorPerformance.java b/test/org/apache/catalina/authenticator/TesterDigestAuthenticatorPerformance.java
index 756d7ae..f064803 100644
--- a/test/org/apache/catalina/authenticator/TesterDigestAuthenticatorPerformance.java
+++ b/test/org/apache/catalina/authenticator/TesterDigestAuthenticatorPerformance.java
@@ -17,8 +17,7 @@
 package org.apache.catalina.authenticator;
 
 import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.servlet.http.HttpServletResponse;
 
@@ -33,6 +32,7 @@ import org.apache.catalina.core.StandardContext;
 import org.apache.catalina.deploy.LoginConfig;
 import org.apache.catalina.filters.TesterResponse;
 import org.apache.catalina.startup.TestTomcat.MapRealm;
+import org.apache.catalina.util.ConcurrentMessageDigest;
 import org.apache.catalina.util.MD5Encoder;
 
 public class TesterDigestAuthenticatorPerformance {
@@ -47,12 +47,14 @@ public class TesterDigestAuthenticatorPerformance {
     private static String REALM = "TestRealm";
     private static String QOP = "auth";
 
+    private static final AtomicInteger nonceCount = new AtomicInteger(0);
+
     private DigestAuthenticator authenticator = new DigestAuthenticator();
 
 
     @Test
     public void testSimple() throws Exception {
-        doTest(100, 1000000);
+        doTest(4, 1000000);
     }
 
     public void doTest(int threadCount, int requestCount) throws Exception {
@@ -60,9 +62,12 @@ public class TesterDigestAuthenticatorPerformance {
         TesterRunnable runnables[] = new TesterRunnable[threadCount];
         Thread threads[] = new Thread[threadCount];
 
+        String nonce = authenticator.generateNonce(new TesterDigestRequest());
+
         // Create the runnables & threads
         for (int i = 0; i < threadCount; i++) {
-            runnables[i] = new TesterRunnable(requestCount);
+            runnables[i] =
+                    new TesterRunnable(authenticator, nonce, requestCount);
             threads[i] = new Thread(runnables[i]);
         }
 
@@ -100,6 +105,8 @@ public class TesterDigestAuthenticatorPerformance {
     @Before
     public void setUp() throws Exception {
 
+        ConcurrentMessageDigest.init("MD5");
+
         // Configure the Realm
         MapRealm realm = new MapRealm();
         realm.addUser(USER, PWD);
@@ -112,16 +119,15 @@ public class TesterDigestAuthenticatorPerformance {
 
         // Make the Context and Realm visible to the Authenticator
         authenticator.setContainer(context);
+        authenticator.setNonceCountWindowSize(8 * 1024);
 
-        // Prevent caching of cnonces so we can the same one for all requests
-        authenticator.setCnonceCacheSize(0);
         authenticator.start();
     }
 
 
-    private class TesterRunnable implements Runnable {
+    private static class TesterRunnable implements Runnable {
 
-        // Number of valid requests required
+        private String nonce;
         private int requestCount;
 
         private int success = 0;
@@ -130,14 +136,26 @@ public class TesterDigestAuthenticatorPerformance {
         private TesterDigestRequest request;
         private HttpServletResponse response;
         private LoginConfig config;
+        private DigestAuthenticator authenticator;
+
+        private static final String A1 = USER + ":" + REALM + ":" + PWD;
+        private static final String A2 = METHOD + ":" + CONTEXT_PATH + URI;
+
+        private static final String MD5A1 = MD5Encoder.encode(
+                ConcurrentMessageDigest.digest("MD5", A1.getBytes()));
+        private static final String MD5A2 = MD5Encoder.encode(
+                ConcurrentMessageDigest.digest("MD5", A2.getBytes()));
+
+
 
         // All init code should be in here. run() needs to be quick
-        public TesterRunnable(int requestCount) throws Exception {
+        public TesterRunnable(DigestAuthenticator authenticator,
+                String nonce, int requestCount) throws Exception {
+            this.authenticator = authenticator;
+            this.nonce = nonce;
             this.requestCount = requestCount;
 
             request = new TesterDigestRequest();
-            String nonce = authenticator.generateNonce(request);
-            request.setAuthHeader(buildDigestResponse(nonce));
 
             response = new TesterResponse();
 
@@ -150,9 +168,12 @@ public class TesterDigestAuthenticatorPerformance {
             long start = System.currentTimeMillis();
             for (int i = 0; i < requestCount; i++) {
                 try {
-                    if (authenticator.authenticate(request, response, config)) {
+                    request.setAuthHeader(buildDigestResponse(nonce));
+                    if (authenticator.authenticate(request, response)) {
                         success++;
                     }
+                    // Clear out authenticated user ready for next iteration
+                    request.setUserPrincipal(null);
                 } catch (IOException ioe) {
                     // Ignore
                 }
@@ -168,26 +189,17 @@ public class TesterDigestAuthenticatorPerformance {
             return time;
         }
 
-        private String buildDigestResponse(String nonce)
-                throws NoSuchAlgorithmException {
+        private String buildDigestResponse(String nonce) {
 
-            String ncString = "00000001";
+            String ncString = String.format("%1$08x",
+                    Integer.valueOf(nonceCount.incrementAndGet()));
             String cnonce = "cnonce";
 
-            String a1 = USER + ":" + REALM + ":" + PWD;
-            String a2 = METHOD + ":" + CONTEXT_PATH + URI;
+            String response = MD5A1 + ":" + nonce + ":" + ncString + ":" +
+                    cnonce + ":" + QOP + ":" + MD5A2;
 
-            MessageDigest digester = MessageDigest.getInstance("MD5");
-            MD5Encoder encoder = new MD5Encoder();
-
-            String md5a1 = encoder.encode(digester.digest(a1.getBytes()));
-            String md5a2 = encoder.encode(digester.digest(a2.getBytes()));
-
-            String response = md5a1 + ":" + nonce + ":" + ncString + ":" +
-                    cnonce + ":" + QOP + ":" + md5a2;
-
-            String md5response =
-                encoder.encode(digester.digest(response.getBytes()));
+            String md5response = MD5Encoder.encode(
+                    ConcurrentMessageDigest.digest("MD5", response.getBytes()));
 
             StringBuilder auth = new StringBuilder();
             auth.append("Digest username=\"");
@@ -203,12 +215,10 @@ public class TesterDigestAuthenticatorPerformance {
             auth.append("\", response=\"");
             auth.append(md5response);
             auth.append("\"");
-            auth.append(", qop=\"");
+            auth.append(", qop=");
             auth.append(QOP);
-            auth.append("\"");
-            auth.append(", nc=\"");
+            auth.append(", nc=");
             auth.append(ncString);
-            auth.append("\"");
             auth.append(", cnonce=\"");
             auth.append(cnonce);
             auth.append("\"");
@@ -254,6 +264,5 @@ public class TesterDigestAuthenticatorPerformance {
         public String getRequestURI() {
             return CONTEXT_PATH + URI;
         }
-
     }
 }
diff --git a/test/org/apache/catalina/comet/TestCometProcessor.java b/test/org/apache/catalina/comet/TestCometProcessor.java
index 8f2a3e1..2812658 100644
--- a/test/org/apache/catalina/comet/TestCometProcessor.java
+++ b/test/org/apache/catalina/comet/TestCometProcessor.java
@@ -635,10 +635,6 @@ public class TestCometProcessor extends TomcatBaseTest {
             return e;
         }
 
-        public void clearResponse() {
-            response = new StringBuilder();
-        }
-
         public String getResponse() {
             return response.toString();
         }
diff --git a/test/org/apache/catalina/connector/TestResponse.java b/test/org/apache/catalina/connector/TestResponse.java
index ac016aa..24cd40e 100644
--- a/test/org/apache/catalina/connector/TestResponse.java
+++ b/test/org/apache/catalina/connector/TestResponse.java
@@ -222,6 +222,172 @@ public class TestResponse extends TomcatBaseTest {
     }
 
 
+    @Test
+    public void testBug53062f() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("bar.html");
+
+        Assert.assertEquals(
+                "http://localhost:8080/level1/level2/bar.html", result);
+    }
+
+
+    @Test
+    public void testBug53062g() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("bar.html?x=/../");
+
+        Assert.assertEquals(
+                "http://localhost:8080/level1/level2/bar.html?x=/../", result);
+    }
+
+
+    @Test
+    public void testBug53062h() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("bar.html?x=/../../");
+
+        Assert.assertEquals(
+                "http://localhost:8080/level1/level2/bar.html?x=/../../",
+                result);
+    }
+
+
+    @Test
+    public void testBug53062i() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("./.?x=/../../");
+
+        Assert.assertEquals(
+                "http://localhost:8080/level1/level2/?x=/../../", result);
+    }
+
+
+    @Test
+    public void testBug53062j() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("./..?x=/../../");
+
+        Assert.assertEquals("http://localhost:8080/level1/?x=/../../", result);
+    }
+
+
+    @Test
+    public void testBug53062k() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("./..?x=/../..");
+
+        Assert.assertEquals(
+                "http://localhost:8080/level1/?x=/../..",
+                result);
+    }
+
+
+    @Test
+    public void testBug53062l() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("bar.html#/../");
+
+        Assert.assertEquals(
+                "http://localhost:8080/level1/level2/bar.html#/../", result);
+    }
+
+
+    @Test
+    public void testBug53062m() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("bar.html#/../../");
+
+        Assert.assertEquals(
+                "http://localhost:8080/level1/level2/bar.html#/../../", result);
+    }
+
+
+    @Test
+    public void testBug53062n() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("./.#/../../");
+
+        Assert.assertEquals(
+                "http://localhost:8080/level1/level2/#/../../", result);
+    }
+
+
+    @Test
+    public void testBug53062o() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("./..#/../../");
+
+        Assert.assertEquals("http://localhost:8080/level1/#/../../", result);
+    }
+
+
+    @Test
+    public void testBug53062p() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.toAbsolute("./..#/../..");
+
+        Assert.assertEquals("http://localhost:8080/level1/#/../..", result);
+    }
+
+
+    @Test
+    public void testBug53469a() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.encodeURL("../bar.html");
+
+        Assert.assertEquals("../bar.html", result);
+    }
+
+
+    @Test
+    public void testBug53469b() throws Exception {
+        Request req = new TesterMockRequest();
+        Response resp = new Response();
+        resp.setRequest(req);
+
+        String result = resp.encodeURL("../../../../bar.html");
+
+        Assert.assertEquals("../../../../bar.html", result);
+    }
+
+
     private static final class Bug52811Servlet extends HttpServlet {
         private static final long serialVersionUID = 1L;
 
diff --git a/test/org/apache/catalina/core/TestApplicationContext.java b/test/org/apache/catalina/core/TestApplicationContext.java
index c78641b..b9c8f1a 100644
--- a/test/org/apache/catalina/core/TestApplicationContext.java
+++ b/test/org/apache/catalina/core/TestApplicationContext.java
@@ -18,6 +18,8 @@ package org.apache.catalina.core;
 
 import java.io.File;
 
+import javax.servlet.http.HttpServletResponse;
+
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -48,4 +50,23 @@ public class TestApplicationContext extends TomcatBaseTest {
             }
         }
     }
+
+
+    @Test
+    public void testBug53467() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp-3.0");
+        // app dir is relative to server home
+        tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+
+        tomcat.start();
+
+        ByteChunk res = new ByteChunk();
+        int rc = getUrl("http://localhost:" + getPort() +
+                "/test/bug53467].jsp", res, null);
+
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+        Assert.assertTrue(res.toString().contains("<p>OK</p>"));
+    }
 }
diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java b/test/org/apache/catalina/core/TestAsyncContextImpl.java
index 9118f35..3b50581 100644
--- a/test/org/apache/catalina/core/TestAsyncContextImpl.java
+++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java
@@ -19,6 +19,7 @@ package org.apache.catalina.core;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -28,6 +29,7 @@ import java.util.concurrent.Executors;
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
 import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequestEvent;
@@ -37,6 +39,8 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import junit.framework.Assert;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -47,6 +51,7 @@ import org.junit.Test;
 import org.apache.catalina.Context;
 import org.apache.catalina.Wrapper;
 import org.apache.catalina.connector.Request;
+import org.apache.catalina.deploy.ErrorPage;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.catalina.valves.TesterAccessLogValve;
@@ -173,7 +178,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         assertEquals("OK-run2", bc2.toString());
 
         // Check the access log
-        alv.validateAccessLog(2, 200,
+        alv.validateAccessLog(2, 500,
                 AsyncStartNoCompleteServlet.ASYNC_TIMEOUT,
                 AsyncStartNoCompleteServlet.ASYNC_TIMEOUT + TIMEOUT_MARGIN +
                         REQUEST_TIME);
@@ -379,29 +384,34 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
     @Test
     public void testTimeoutListenerCompleteNoDispatch() throws Exception {
         // Should work
-        doTestTimeout(true, null);
+        doTestTimeout(Boolean.TRUE, null);
     }
 
     @Test
     public void testTimeoutListenerNoCompleteNoDispatch() throws Exception {
         // Should trigger an error - must do one or other
-        doTestTimeout(false, null);
+        doTestTimeout(Boolean.FALSE, null);
     }
 
     @Test
     public void testTimeoutListenerCompleteDispatch() throws Exception {
         // Should trigger an error - can't do both
-        doTestTimeout(true, "/nonasync");
+        doTestTimeout(Boolean.TRUE, "/nonasync");
     }
 
     @Test
     public void testTimeoutListenerNoCompleteDispatch() throws Exception {
         // Should work
-        doTestTimeout(false, "/nonasync");
+        doTestTimeout(Boolean.FALSE, "/nonasync");
     }
 
+    @Test
+    public void testTimeoutNoListener() throws Exception {
+        // Should work
+        doTestTimeout(null, null);
+    }
 
-    private void doTestTimeout(boolean completeOnTimeout, String dispatchUrl)
+    private void doTestTimeout(Boolean completeOnTimeout, String dispatchUrl)
     throws Exception {
         // Setup Tomcat instance
         Tomcat tomcat = getTomcatInstance();
@@ -419,7 +429,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
 
         TimeoutServlet timeout =
-            new TimeoutServlet(completeOnTimeout, dispatchUrl);
+                new TimeoutServlet(completeOnTimeout, dispatchUrl);
 
         Wrapper wrapper = Tomcat.addServlet(ctx, "time", timeout);
         wrapper.setAsyncSupported(true);
@@ -446,8 +456,11 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
             // Ignore - expected for some error conditions
         }
         StringBuilder expected = new StringBuilder("requestInitialized-");
-        expected.append("TimeoutServletGet-onTimeout-");
-        if (completeOnTimeout) {
+        expected.append("TimeoutServletGet-");
+        if (completeOnTimeout == null) {
+            expected.append("requestDestroyed");
+        } else if (completeOnTimeout.booleanValue()) {
+            expected.append("onTimeout-");
             if (dispatchUrl == null) {
                 expected.append("onComplete-");
                 expected.append("requestDestroyed");
@@ -458,9 +471,8 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
                 // never happens.
             }
         } else {
-            if (dispatchUrl == null) {
-                expected.append("onError-");
-            } else {
+            expected.append("onTimeout-");
+            if (dispatchUrl != null) {
                 expected.append("NonAsyncServletGet-");
             }
             expected.append("onComplete-");
@@ -469,7 +481,14 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         assertEquals(expected.toString(), res.toString());
 
         // Check the access log
-        if (completeOnTimeout && dispatchUrl != null) {
+        if (completeOnTimeout == null) {
+            alvGlobal.validateAccessLog(1, 500, TimeoutServlet.ASYNC_TIMEOUT,
+                    TimeoutServlet.ASYNC_TIMEOUT + TIMEOUT_MARGIN +
+                    REQUEST_TIME);
+            alv.validateAccessLog(1, 500, TimeoutServlet.ASYNC_TIMEOUT,
+                    TimeoutServlet.ASYNC_TIMEOUT + TIMEOUT_MARGIN +
+                    REQUEST_TIME);
+        } else if (completeOnTimeout.booleanValue() && dispatchUrl != null) {
             // This error is written into Host-level AccessLogValve only
             alvGlobal.validateAccessLog(1, 500, 0, TimeoutServlet.ASYNC_TIMEOUT
                     + TIMEOUT_MARGIN + REQUEST_TIME);
@@ -487,12 +506,12 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
     private static class TimeoutServlet extends HttpServlet {
         private static final long serialVersionUID = 1L;
 
-        private final boolean completeOnTimeout;
+        private final Boolean completeOnTimeout;
         private final String dispatchUrl;
 
         public static final long ASYNC_TIMEOUT = 3000;
 
-        public TimeoutServlet(boolean completeOnTimeout, String dispatchUrl) {
+        public TimeoutServlet(Boolean completeOnTimeout, String dispatchUrl) {
             this.completeOnTimeout = completeOnTimeout;
             this.dispatchUrl = dispatchUrl;
         }
@@ -505,8 +524,10 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
                 final AsyncContext ac = req.startAsync();
                 ac.setTimeout(ASYNC_TIMEOUT);
 
-                ac.addListener(new TrackingListener(
-                        false, completeOnTimeout, dispatchUrl));
+                if (completeOnTimeout != null) {
+                    ac.addListener(new TrackingListener(false,
+                            completeOnTimeout.booleanValue(), dispatchUrl));
+                }
             } else {
                 resp.getWriter().print("FAIL: Async unsupported");
             }
@@ -597,6 +618,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
 
         private static final long serialVersionUID = 1L;
         private static final String ITER_PARAM = "iter";
+        private static final String DISPATCH_CHECK = "check";
         private boolean addTrackingListener = false;
         private boolean completeOnError = false;
 
@@ -610,6 +632,11 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                 throws ServletException, IOException {
 
+            if ("y".equals(req.getParameter(DISPATCH_CHECK))) {
+                if (req.getDispatcherType() != DispatcherType.ASYNC) {
+                    resp.getWriter().write("WrongDispatcherType-");
+                }
+            }
             resp.getWriter().write("DispatchingServletGet-");
             resp.flushBuffer();
             final int iter = Integer.parseInt(req.getParameter(ITER_PARAM)) - 1;
@@ -623,7 +650,8 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
                 @Override
                 public void run() {
                     if (iter > 0) {
-                        ctxt.dispatch("/stage1?" + ITER_PARAM + "=" + iter);
+                        ctxt.dispatch("/stage1?" + ITER_PARAM + "=" + iter +
+                                "&" + DISPATCH_CHECK + "=y");
                     } else {
                         ctxt.dispatch("/stage2");
                     }
@@ -664,7 +692,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         wrapper.setAsyncSupported(true);
         ctx.addServletMapping("/stage1", "tracking");
 
-        TimeoutServlet timeout = new TimeoutServlet(true, null);
+        TimeoutServlet timeout = new TimeoutServlet(Boolean.TRUE, null);
         Wrapper wrapper2 = Tomcat.addServlet(ctx, "timeout", timeout);
         wrapper2.setAsyncSupported(true);
         ctx.addServletMapping("/stage2", "timeout");
@@ -1360,4 +1388,246 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         }
     }
 
+    @Test
+    public void testBug53843() throws Exception {
+        // Setup Tomcat instance
+        Tomcat tomcat = getTomcatInstance();
+
+        // Must have a real docBase - just use temp
+        File docBase = new File(System.getProperty("java.io.tmpdir"));
+
+        Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
+        Bug53843ServletA servletA = new Bug53843ServletA();
+        Wrapper a = Tomcat.addServlet(ctx, "ServletA", servletA);
+        a.setAsyncSupported(true);
+        Tomcat.addServlet(ctx, "ServletB", new Bug53843ServletB());
+
+        ctx.addServletMapping("/ServletA", "ServletA");
+        ctx.addServletMapping("/ServletB", "ServletB");
+
+        tomcat.start();
+
+        StringBuilder url = new StringBuilder(48);
+        url.append("http://localhost:");
+        url.append(getPort());
+        url.append("/ServletA");
+
+        ByteChunk body = new ByteChunk();
+        int rc = getUrl(url.toString(), body, null);
+
+        assertEquals(HttpServletResponse.SC_OK, rc);
+        assertEquals("OK", body.toString());
+        assertTrue(servletA.isAsyncWhenExpected());
+    }
+
+    private static class Bug53843ServletA extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        private boolean isAsyncWhenExpected = true;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+
+            // Should not be async at this point
+            isAsyncWhenExpected = isAsyncWhenExpected && !req.isAsyncStarted();
+
+            final AsyncContext async = req.startAsync();
+
+            // Should be async at this point
+            isAsyncWhenExpected = isAsyncWhenExpected && req.isAsyncStarted();
+
+            async.start(new Runnable() {
+
+                @Override
+                public void run() {
+                    // This should be delayed until the original container
+                    // thread exists
+                    async.dispatch("/ServletB");
+                }
+            });
+
+            try {
+                Thread.sleep(3000);
+            } catch (InterruptedException e) {
+                throw new ServletException(e);
+            }
+
+            // Should be async at this point
+            isAsyncWhenExpected = isAsyncWhenExpected && req.isAsyncStarted();
+        }
+
+        public boolean isAsyncWhenExpected() {
+            return isAsyncWhenExpected;
+        }
+    }
+
+    private static class Bug53843ServletB extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            resp.setContentType("text/plain");
+            resp.getWriter().print("OK");
+        }
+    }
+
+    @Test
+    public void testTimeoutErrorDispatchNone() throws Exception {
+        doTestTimeoutErrorDispatch(null, null);
+    }
+
+    @Test
+    public void testTimeoutErrorDispatchNonAsync() throws Exception {
+        doTestTimeoutErrorDispatch(Boolean.FALSE, null);
+    }
+
+    @Test
+    public void testTimeoutErrorDispatchAsyncStart() throws Exception {
+        doTestTimeoutErrorDispatch(
+                Boolean.TRUE, ErrorPageAsyncMode.NO_COMPLETE);
+    }
+
+    @Test
+    public void testTimeoutErrorDispatchAsyncComplete() throws Exception {
+        doTestTimeoutErrorDispatch(Boolean.TRUE, ErrorPageAsyncMode.COMPLETE);
+    }
+
+    @Test
+    public void testTimeoutErrorDispatchAsyncDispatch() throws Exception {
+        doTestTimeoutErrorDispatch(Boolean.TRUE, ErrorPageAsyncMode.DISPATCH);
+    }
+
+    private void doTestTimeoutErrorDispatch(Boolean asyncError,
+            ErrorPageAsyncMode mode) throws Exception {
+        // Setup Tomcat instance
+        Tomcat tomcat = getTomcatInstance();
+
+        // Must have a real docBase - just use temp
+        File docBase = new File(System.getProperty("java.io.tmpdir"));
+
+        Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
+
+        TimeoutServlet timeout = new TimeoutServlet(null, null);
+        Wrapper w1 = Tomcat.addServlet(ctx, "time", timeout);
+        w1.setAsyncSupported(true);
+        ctx.addServletMapping("/async", "time");
+
+        NonAsyncServlet nonAsync = new NonAsyncServlet();
+        Wrapper w2 = Tomcat.addServlet(ctx, "nonAsync", nonAsync);
+        w2.setAsyncSupported(true);
+        ctx.addServletMapping("/error/nonasync", "nonAsync");
+
+        AsyncErrorPage asyncErrorPage = new AsyncErrorPage(mode);
+        Wrapper w3 = Tomcat.addServlet(ctx, "asyncErrorPage", asyncErrorPage);
+        w3.setAsyncSupported(true);
+        ctx.addServletMapping("/error/async", "asyncErrorPage");
+
+        if (asyncError != null) {
+            ErrorPage ep = new ErrorPage();
+            ep.setErrorCode(500);
+            if (asyncError.booleanValue()) {
+                ep.setLocation("/error/async");
+            } else {
+                ep.setLocation("/error/nonasync");
+            }
+
+            ctx.addErrorPage(ep);
+        }
+
+        ctx.addApplicationListener(TrackingRequestListener.class.getName());
+
+        TesterAccessLogValve alv = new TesterAccessLogValve();
+        ctx.getPipeline().addValve(alv);
+        TesterAccessLogValve alvGlobal = new TesterAccessLogValve();
+        tomcat.getHost().getPipeline().addValve(alvGlobal);
+
+        tomcat.start();
+        ByteChunk res = new ByteChunk();
+        try {
+            getUrl("http://localhost:" + getPort() + "/async", res, null);
+        } catch (IOException ioe) {
+            // Ignore - expected for some error conditions
+        }
+
+        StringBuilder expected = new StringBuilder();
+        if (asyncError == null) {
+            // No error handler - just get the 500 response
+            expected.append("requestInitialized-TimeoutServletGet-");
+            // Note: With an error handler the response will be reset and these
+            //       will be lost
+        }
+        if (asyncError != null) {
+            if (asyncError.booleanValue()) {
+                expected.append("AsyncErrorPageGet-");
+                if (mode == ErrorPageAsyncMode.NO_COMPLETE){
+                    expected.append("NoOp-");
+                } else if (mode == ErrorPageAsyncMode.COMPLETE) {
+                    expected.append("Complete-");
+                } else if (mode == ErrorPageAsyncMode.DISPATCH) {
+                    expected.append("Dispatch-NonAsyncServletGet-");
+                }
+            } else {
+                expected.append("NonAsyncServletGet-");
+            }
+        }
+        expected.append("requestDestroyed");
+
+        Assert.assertEquals(expected.toString(), res.toString());
+
+        // Check the access log
+        alvGlobal.validateAccessLog(1, 500, TimeoutServlet.ASYNC_TIMEOUT,
+                TimeoutServlet.ASYNC_TIMEOUT + TIMEOUT_MARGIN +
+                REQUEST_TIME);
+        alv.validateAccessLog(1, 500, TimeoutServlet.ASYNC_TIMEOUT,
+                TimeoutServlet.ASYNC_TIMEOUT + TIMEOUT_MARGIN +
+                REQUEST_TIME);
+    }
+
+    private static enum ErrorPageAsyncMode {
+        NO_COMPLETE,
+        COMPLETE,
+        DISPATCH
+    }
+
+    private static class AsyncErrorPage extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        private final ErrorPageAsyncMode mode;
+
+        public AsyncErrorPage(ErrorPageAsyncMode mode) {
+            this.mode = mode;
+        }
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            PrintWriter writer = resp.getWriter();
+            writer.write("AsyncErrorPageGet-");
+            resp.flushBuffer();
+
+            final AsyncContext ctxt = req.getAsyncContext();
+
+            switch(mode) {
+                case COMPLETE:
+                    writer.write("Complete-");
+                    ctxt.complete();
+                    break;
+                case DISPATCH:
+                    writer.write("Dispatch-");
+                    ctxt.dispatch("/error/nonasync");
+                    break;
+                case NO_COMPLETE:
+                    writer.write("NoOp-");
+                    break;
+                default:
+                    // Impossible
+                    break;
+            }
+        }
+    }
 }
diff --git a/test/org/apache/catalina/core/TestNamingContextListener.java b/test/org/apache/catalina/core/TestNamingContextListener.java
index 630a0e6..c7e7457 100644
--- a/test/org/apache/catalina/core/TestNamingContextListener.java
+++ b/test/org/apache/catalina/core/TestNamingContextListener.java
@@ -33,8 +33,13 @@ import org.apache.catalina.startup.TomcatBaseTest;
 
 public class TestNamingContextListener extends TomcatBaseTest {
 
-    private static final String JNDI_NAME = "TestName";
-    private static final String JNDI_VALUE= "Test Value";
+    private static final String BUG49132_NAME = "TestName";
+    private static final String BUG49132_VALUE = "Test Value";
+
+    private static final String BUG54096_NameA = "envA";
+    private static final String BUG54096_ValueA = "valueA";
+    private static final String BUG54096_NameB = "envB";
+    private static final String BUG54096_ValueB = "B";
 
     /**
      * Test JNDI is available to ServletContextListeners.
@@ -51,9 +56,9 @@ public class TestNamingContextListener extends TomcatBaseTest {
         tomcat.enableNaming();
 
         ContextEnvironment environment = new ContextEnvironment();
-        environment.setType(JNDI_VALUE.getClass().getName());
-        environment.setName(JNDI_NAME);
-        environment.setValue(JNDI_VALUE);
+        environment.setType(BUG49132_VALUE.getClass().getName());
+        environment.setName(BUG49132_NAME);
+        environment.setValue(BUG49132_VALUE);
         ctx.getNamingResources().addEnvironment(environment);
 
         ctx.addApplicationListener(Bug49132Listener.class.getName());
@@ -77,8 +82,8 @@ public class TestNamingContextListener extends TomcatBaseTest {
                 initCtx = new InitialContext();
                 javax.naming.Context envCtx =
                     (javax.naming.Context) initCtx.lookup("java:comp/env");
-                String value = (String) envCtx.lookup(JNDI_NAME);
-                if (!JNDI_VALUE.equals(value)) {
+                String value = (String) envCtx.lookup(BUG49132_NAME);
+                if (!BUG49132_VALUE.equals(value)) {
                     throw new RuntimeException();
                 }
             } catch (NamingException e) {
@@ -87,4 +92,95 @@ public class TestNamingContextListener extends TomcatBaseTest {
         }
     }
 
+    @Test
+    public void testBug54096() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        // Must have a real docBase - just use temp
+        org.apache.catalina.Context ctx =
+            tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+
+        // Enable JNDI - it is disabled by default
+        tomcat.enableNaming();
+
+        ContextEnvironment environmentA = new ContextEnvironment();
+        environmentA.setType(Bug54096EnvA.class.getName());
+        environmentA.setName(BUG54096_NameA);
+        environmentA.setValue(BUG54096_ValueA);
+        ctx.getNamingResources().addEnvironment(environmentA);
+
+        ContextEnvironment environmentB = new ContextEnvironment();
+        environmentB.setType(Bug54096EnvB.class.getName());
+        environmentB.setName(BUG54096_NameB);
+        environmentB.setValue(BUG54096_ValueB);
+        ctx.getNamingResources().addEnvironment(environmentB);
+
+        ctx.addApplicationListener(Bug54096Listener.class.getName());
+
+        tomcat.start();
+
+        assertEquals(LifecycleState.STARTED, ctx.getState());
+    }
+
+    public static class Bug54096EnvA {
+
+        private final String value;
+
+        public Bug54096EnvA(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+    public static class Bug54096EnvB {
+
+        private final char value;
+
+        public Bug54096EnvB(char value) {
+            this.value = value;
+        }
+
+        public char getValue() {
+            return value;
+        }
+    }
+
+    public static final class Bug54096Listener implements
+            ServletContextListener {
+
+        @Override
+        public void contextDestroyed(ServletContextEvent sce) {
+            // NOOP
+        }
+
+        @Override
+        public void contextInitialized(ServletContextEvent sce) {
+            javax.naming.Context initCtx;
+            try {
+                initCtx = new InitialContext();
+                javax.naming.Context envCtx =
+                    (javax.naming.Context) initCtx.lookup("java:comp/env");
+
+                // Validate entry A
+                Bug54096EnvA valueA =
+                        (Bug54096EnvA) envCtx.lookup(BUG54096_NameA);
+                if (!BUG54096_ValueA.equals(valueA.getValue())) {
+                    throw new RuntimeException();
+                }
+
+                // Validate entry B
+                Bug54096EnvB valueB =
+                        (Bug54096EnvB) envCtx.lookup(BUG54096_NameB);
+                if (BUG54096_ValueB.charAt(0) != valueB.getValue()) {
+                    throw new RuntimeException();
+                }
+
+            } catch (NamingException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
 }
diff --git a/test/org/apache/catalina/core/TestStandardHostValve.java b/test/org/apache/catalina/core/TestStandardHostValve.java
new file mode 100644
index 0000000..119a1c0
--- /dev/null
+++ b/test/org/apache/catalina/core/TestStandardHostValve.java
@@ -0,0 +1,110 @@
+/*
+ *  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 java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.ErrorPage;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+public class TestStandardHostValve extends TomcatBaseTest {
+
+    @Test
+    public void testErrorPageHandling() throws Exception {
+        // Set up a container
+        Tomcat tomcat = getTomcatInstance();
+
+        // Must have a real docBase - just use temp
+        File docBase = new File(System.getProperty("java.io.tmpdir"));
+        Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
+
+        // Add the error page
+        Tomcat.addServlet(ctx, "error", new ErrorServlet());
+        ctx.addServletMapping("/error", "error");
+
+        // Add the error handling page
+        Tomcat.addServlet(ctx, "report", new ReportServlet());
+        ctx.addServletMapping("/report/*", "report");
+
+        // And the handling for 500 responses
+        ErrorPage errorPage500 = new ErrorPage();
+        errorPage500.setErrorCode(Response.SC_INTERNAL_SERVER_ERROR);
+        errorPage500.setLocation("/report/500");
+        ctx.addErrorPage(errorPage500);
+
+        // And the default error handling
+        ErrorPage errorPageDefault = new ErrorPage();
+        errorPageDefault.setLocation("/report/default");
+        ctx.addErrorPage(errorPageDefault);
+
+        tomcat.start();
+
+        doTestErrorPageHandling(500, "/500");
+        doTestErrorPageHandling(501, "/default");
+    }
+
+    private void doTestErrorPageHandling(int error, String report)
+            throws Exception {
+
+        // Request a page that triggers an error
+        ByteChunk bc = new ByteChunk();
+        int rc = getUrl("http://localhost:" + getPort() +
+                "/error?errorCode=" + error, bc, null);
+
+        Assert.assertEquals(error, rc);
+        Assert.assertEquals(report, bc.toString());
+    }
+
+    private static class ErrorServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            int error =
+                    Integer.valueOf(req.getParameter("errorCode")).intValue();
+            resp.sendError(error);
+        }
+    }
+
+    private static class ReportServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            String pathInfo = req.getPathInfo();
+            resp.setContentType("text/plain");
+            resp.getWriter().print(pathInfo);
+        }
+    }
+}
diff --git a/test/org/apache/catalina/deploy/TestWebXmlOrdering.java b/test/org/apache/catalina/deploy/TestWebXmlOrdering.java
index edfb5a1..76aa420 100644
--- a/test/org/apache/catalina/deploy/TestWebXmlOrdering.java
+++ b/test/org/apache/catalina/deploy/TestWebXmlOrdering.java
@@ -17,9 +17,11 @@
 
 package org.apache.catalina.deploy;
 
-import java.util.HashMap;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -42,9 +44,15 @@ public class TestWebXmlOrdering {
     private WebXml e;
     private WebXml f;
     private Map<String,WebXml> fragments;
+    private int posA;
+    private int posB;
+    private int posC;
+    private int posD;
+    private int posE;
+    private int posF;
 
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
         app = new WebXml();
         a = new WebXml();
         a.setName("a");
@@ -58,7 +66,8 @@ public class TestWebXmlOrdering {
         e.setName("e");
         f = new WebXml();
         f.setName("f");
-        fragments = new HashMap<String,WebXml>();
+        // Control the input order
+        fragments = new LinkedHashMap<String,WebXml>();
         fragments.put("a",a);
         fragments.put("b",b);
         fragments.put("c",c);
@@ -185,83 +194,507 @@ public class TestWebXmlOrdering {
         assertFalse(iter.hasNext());
     }
 
+    private void doRelativeOrderingTest(RelativeOrderingTestRunner runner) {
+        // Confirm we have all 720 possible input orders
+        // Set<String> orders = new HashSet<>();
+
+        // Test all possible input orders since some bugs were discovered that
+        // depended on input order
+        for (int i = 0; i < 6; i++) {
+            for (int j = 0; j < 5; j++) {
+                for (int k = 0; k < 4; k++) {
+                    for (int l = 0; l < 3; l++) {
+                        for (int m = 0; m < 2; m++) {
+                            setUp();
+                            runner.init();
+                            ArrayList<WebXml> source = new ArrayList<WebXml>();
+                            source.addAll(fragments.values());
+                            Map<String,WebXml> input =
+                                    new LinkedHashMap<String,WebXml>();
+
+                            WebXml one = source.remove(i);
+                            input.put(one.getName(), one);
+
+                            WebXml two = source.remove(j);
+                            input.put(two.getName(), two);
+
+                            WebXml three = source.remove(k);
+                            input.put(three.getName(), three);
+
+                            WebXml four = source.remove(l);
+                            input.put(four.getName(), four);
+
+                            WebXml five = source.remove(m);
+                            input.put(five.getName(), five);
+
+                            WebXml six = source.remove(0);
+                            input.put(six.getName(), six);
+
+                            /*
+                            String order = one.getName() + two.getName() +
+                                    three.getName() + four.getName() +
+                                    five.getName() + six.getName();
+                            orders.add(order);
+                            */
+
+                            Set<WebXml> ordered =
+                                    WebXml.orderWebFragments(app, input);
+                            populatePositions(ordered);
+
+                            runner.validate(getOrder(ordered));
+                        }
+                    }
+                }
+            }
+        }
+        // System.out.println(orders.size());
+    }
+
+    private String getOrder(Set<WebXml> ordered) {
+        StringBuilder sb = new StringBuilder(ordered.size());
+        for (WebXml webXml : ordered) {
+            sb.append(webXml.getName());
+        }
+        return sb.toString();
+    }
+
+    private void populatePositions(Set<WebXml> ordered) {
+        List<WebXml> indexed = new ArrayList<WebXml>();
+        indexed.addAll(ordered);
+
+        posA = indexed.indexOf(a);
+        posB = indexed.indexOf(b);
+        posC = indexed.indexOf(c);
+        posD = indexed.indexOf(d);
+        posE = indexed.indexOf(e);
+        posF = indexed.indexOf(f);
+    }
+
     @Test
     public void testOrderWebFragmentsRelative1() {
         // First example from servlet spec
-        a.addAfterOrderingOthers();
-        a.addAfterOrdering("c");
-        b.addBeforeOrderingOthers();
-        c.addAfterOrderingOthers();
-        f.addBeforeOrderingOthers();
-        f.addBeforeOrdering("b");
-
-        Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments);
-
-        Iterator<WebXml> iter = ordered.iterator();
-        assertEquals(f,iter.next());
-        assertEquals(b,iter.next());
-        assertEquals(d,iter.next());
-        assertEquals(e,iter.next());
-        assertEquals(c,iter.next());
-        assertEquals(a,iter.next());
+        doRelativeOrderingTest(new RelativeTestRunner1());
     }
 
     @Test
     public void testOrderWebFragmentsRelative2() {
         // Second example - use fragment a for no-id fragment
-        a.addAfterOrderingOthers();
-        a.addBeforeOrdering("c");
-        b.addBeforeOrderingOthers();
-        d.addAfterOrderingOthers();
-        e.addBeforeOrderingOthers();
+        doRelativeOrderingTest(new RelativeTestRunner2());
+    }
 
-        Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments);
+    @Test
+    public void testOrderWebFragmentsRelative3() {
+        // Third example from spec with e & f added
+        doRelativeOrderingTest(new RelativeTestRunner3());
+    }
 
-        Iterator<WebXml> iter = ordered.iterator();
-        // A number of orders are possible but the algorithm is deterministic
-        // and this order is valid. If this fails after a change to the
-        // algorithm, then check to see if the new order is also valid.
-        assertEquals(b,iter.next());
-        assertEquals(e,iter.next());
-        assertEquals(f,iter.next());
-        assertEquals(a,iter.next());
-        assertEquals(c,iter.next());
-        assertEquals(d,iter.next());
+    @Test
+    public void testOrderWebFragmentsRelative4Bug54068() {
+        // Simple sequence that failed for some inputs
+        doRelativeOrderingTest(new RelativeTestRunner4());
     }
 
     @Test
-    public void testOrderWebFragmentsRelative3() {
-        // Third example from spec
-        a.addAfterOrdering("b");
-        c.addBeforeOrderingOthers();
-        fragments.remove("e");
-        fragments.remove("f");
+    public void testOrderWebFragmentsRelative5Bug54068() {
+        // Simple sequence that failed for some inputs
+        doRelativeOrderingTest(new RelativeTestRunner5());
+    }
 
-        Set<WebXml> ordered = WebXml.orderWebFragments(app, fragments);
+    @Test
+    public void testOrderWebFragmentsRelative6Bug54068() {
+        // Simple sequence that failed for some inputs
+        doRelativeOrderingTest(new RelativeTestRunner6());
+    }
 
-        Iterator<WebXml> iter = ordered.iterator();
-        // A number of orders are possible but the algorithm is deterministic
-        // and this order is valid. If this fails after a change to the
-        // algorithm, then check to see if the new order is also valid.
-        assertEquals(c,iter.next());
-        assertEquals(d,iter.next());
-        assertEquals(b,iter.next());
-        assertEquals(a,iter.next());
+    @Test
+    public void testOrderWebFragmentsRelative7() {
+        // Reference loop (but not circular dependencies)
+        doRelativeOrderingTest(new RelativeTestRunner7());
+    }
+
+    @Test
+    public void testOrderWebFragmentsRelative8() {
+        // More complex, trying to break the algorithm
+        doRelativeOrderingTest(new RelativeTestRunner8());
     }
 
     @Test
-    public void testOrderWebFragmentsrelativeCircular() {
+    public void testOrderWebFragmentsRelative9() {
+        // Variation on bug 54068
+        doRelativeOrderingTest(new RelativeTestRunner9());
+    }
+
+    @Test
+    public void testOrderWebFragmentsRelative10() {
+        // Variation on bug 54068
+        doRelativeOrderingTest(new RelativeTestRunner10());
+    }
+
+    @Test
+    public void testOrderWebFragmentsRelative11() {
+        // Test references to non-existant fragments
+        doRelativeOrderingTest(new RelativeTestRunner11());
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testOrderWebFragmentsrelativeCircular1() {
         a.addBeforeOrdering("b");
         b.addBeforeOrdering("a");
 
-        Exception exception = null;
+        WebXml.orderWebFragments(app, fragments);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testOrderWebFragmentsrelativeCircular2() {
+        a.addBeforeOrderingOthers();
+        b.addAfterOrderingOthers();
+        c.addBeforeOrdering("a");
+        c.addAfterOrdering("b");
+
+        WebXml.orderWebFragments(app, fragments);
+    }
+
+    private interface RelativeOrderingTestRunner {
+        void init();
+        void validate(String order);
+    }
+
+    private class RelativeTestRunner1 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            a.addAfterOrderingOthers();
+            a.addAfterOrdering("c");
+            b.addBeforeOrderingOthers();
+            c.addAfterOrderingOthers();
+            f.addBeforeOrderingOthers();
+            f.addBeforeOrdering("b");
+        }
 
-        try {
-            WebXml.orderWebFragments(app, fragments);
-        } catch (Exception e1) {
-            exception = e1;
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            //a.addAfterOrderingOthers();
+            assertTrue(order, posA > posB);
+            assertTrue(order, posA > posC);
+            assertTrue(order, posA > posD);
+            assertTrue(order, posA > posE);
+            assertTrue(order, posA > posF);
+
+            // a.addAfterOrdering("c");
+            assertTrue(order, posA > posC);
+
+            // b.addBeforeOrderingOthers();
+            assertTrue(order, posB < posC);
+
+            // c.addAfterOrderingOthers();
+            assertTrue(order, posC > posB);
+            assertTrue(order, posC > posD);
+            assertTrue(order, posC > posE);
+            assertTrue(order, posC > posF);
+
+            // f.addBeforeOrderingOthers();
+            assertTrue(order, posF < posA);
+            assertTrue(order, posF < posB);
+            assertTrue(order, posF < posC);
+            assertTrue(order, posF < posD);
+            assertTrue(order, posF < posE);
+
+            // f.addBeforeOrdering("b");
+            assertTrue(order, posF < posB);
         }
+    }
+
+    private class RelativeTestRunner2 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            a.addAfterOrderingOthers();
+            a.addBeforeOrdering("c");
+            b.addBeforeOrderingOthers();
+            d.addAfterOrderingOthers();
+            e.addBeforeOrderingOthers();
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // a.addAfterOrderingOthers();
+            assertTrue(order, posA > posB);
+            assertTrue(order, posA > posE);
+            assertTrue(order, posA > posF);
+
+            // a.addBeforeOrdering("c");
+            assertTrue(order, posC > posA);
+            assertTrue(order, posC > posB);
+            assertTrue(order, posC > posE);
+            assertTrue(order, posC > posF);
+
+            // b.addBeforeOrderingOthers();
+            assertTrue(order, posB < posA);
+            assertTrue(order, posB < posC);
+            assertTrue(order, posB < posD);
+            assertTrue(order, posB < posF);
+
+            // d.addAfterOrderingOthers();
+            assertTrue(order, posD > posB);
+            assertTrue(order, posD > posE);
+            assertTrue(order, posD > posF);
+
+            // e.addBeforeOrderingOthers();
+            assertTrue(order, posE < posA);
+            assertTrue(order, posE < posC);
+            assertTrue(order, posE < posD);
+            assertTrue(order, posE < posF);
+        }
+    }
+
+    private class RelativeTestRunner3 implements RelativeOrderingTestRunner {
 
-        assertTrue(exception instanceof IllegalArgumentException);
+        @Override
+        public void init() {
+            a.addAfterOrdering("b");
+            c.addBeforeOrderingOthers();
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // a.addAfterOrdering("b");
+            assertTrue(order, posA > posB);
+
+            // c.addBeforeOrderingOthers();
+            assertTrue(order, posC < posA);
+            assertTrue(order, posC < posB);
+            assertTrue(order, posC < posD);
+            assertTrue(order, posC < posE);
+            assertTrue(order, posC < posF);
+        }
+    }
+
+    private class RelativeTestRunner4 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            b.addAfterOrdering("a");
+            c.addAfterOrdering("b");
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // b.addAfterOrdering("a");
+            assertTrue(order, posB > posA);
+
+            // c.addAfterOrdering("b");
+            assertTrue(order, posC > posB);
+        }
+    }
+
+    private class RelativeTestRunner5 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            b.addBeforeOrdering("a");
+            c.addBeforeOrdering("b");
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // b.addBeforeOrdering("a");
+            assertTrue(order, posB < posA);
+
+            // c.addBeforeOrdering("b");
+            assertTrue(order, posC < posB);
+        }
+    }
+
+    private class RelativeTestRunner6 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            b.addBeforeOrdering("a");
+            b.addAfterOrdering("c");
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // b.addBeforeOrdering("a");
+            assertTrue(order, posB < posA);
+
+            //b.addAfterOrdering("c");
+            assertTrue(order, posB > posC);
+        }
+    }
+
+    private class RelativeTestRunner7 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            b.addBeforeOrdering("a");
+            c.addBeforeOrdering("b");
+            a.addAfterOrdering("c");
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // b.addBeforeOrdering("a");
+            assertTrue(order, posB < posA);
+
+            // c.addBeforeOrdering("b");
+            assertTrue(order, posC < posB);
+
+            // a.addAfterOrdering("c");
+            assertTrue(order, posA > posC);
+        }
+    }
+
+    private class RelativeTestRunner8 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            a.addBeforeOrderingOthers();
+            a.addBeforeOrdering("b");
+            b.addBeforeOrderingOthers();
+            c.addAfterOrdering("b");
+            d.addAfterOrdering("c");
+            e.addAfterOrderingOthers();
+            f.addAfterOrderingOthers();
+            f.addAfterOrdering("e");
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // a.addBeforeOrderingOthers();
+            assertTrue(order, posA < posB);
+            assertTrue(order, posA < posC);
+            assertTrue(order, posA < posD);
+            assertTrue(order, posA < posE);
+            assertTrue(order, posA < posF);
+
+            // a.addBeforeOrdering("b");
+            assertTrue(order, posA < posB);
+
+            // b.addBeforeOrderingOthers();
+            assertTrue(order, posB < posC);
+            assertTrue(order, posB < posD);
+            assertTrue(order, posB < posE);
+            assertTrue(order, posB < posF);
+
+            // c.addAfterOrdering("b");
+            assertTrue(order, posC > posB);
+
+            // d.addAfterOrdering("c");
+            assertTrue(order, posD > posC);
+
+            // e.addAfterOrderingOthers();
+            assertTrue(order, posE > posA);
+            assertTrue(order, posE > posB);
+            assertTrue(order, posE > posC);
+            assertTrue(order, posE > posD);
+
+            // f.addAfterOrderingOthers();
+            assertTrue(order, posF > posA);
+            assertTrue(order, posF > posB);
+            assertTrue(order, posF > posC);
+            assertTrue(order, posF > posD);
+            assertTrue(order, posF > posE);
+
+            // f.addAfterOrdering("e");
+            assertTrue(order, posF > posE);
+        }
+    }
+
+    private class RelativeTestRunner9 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            a.addBeforeOrderingOthers();
+            b.addBeforeOrdering("a");
+            c.addBeforeOrdering("b");
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // a.addBeforeOrderingOthers();
+            assertTrue(order, posA < posD);
+            assertTrue(order, posA < posE);
+            assertTrue(order, posA < posF);
+
+            // b.addBeforeOrdering("a");
+            assertTrue(order, posB < posA);
+
+            // c.addBeforeOrdering("b");
+            assertTrue(order, posC < posB);
+        }
+    }
+
+    private class RelativeTestRunner10 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            a.addAfterOrderingOthers();
+            b.addAfterOrdering("a");
+            c.addAfterOrdering("b");
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // a.addAfterOrderingOthers();
+            assertTrue(order, posA > posD);
+            assertTrue(order, posA > posE);
+            assertTrue(order, posA > posF);
+
+            // b.addAfterOrdering("a");
+            assertTrue(order, posB > posA);
+
+            // c.addAfterOrdering("b");
+            assertTrue(order, posC > posB);
+        }
+    }
+
+    private class RelativeTestRunner11 implements RelativeOrderingTestRunner {
+
+        @Override
+        public void init() {
+            a.addAfterOrdering("b");
+            b.addAfterOrdering("z");
+            b.addBeforeOrdering("y");
+        }
+
+        @Override
+        public void validate(String order) {
+            // There is some duplication in the tests below - it is easier to
+            // check the tests are complete this way.
+
+            // a.addAfterOrdering("b");
+            assertTrue(order, posA > posB);
+        }
     }
 }
diff --git a/test/org/apache/catalina/startup/SimpleHttpClient.java b/test/org/apache/catalina/startup/SimpleHttpClient.java
index 5a48b7e..3bea2df 100644
--- a/test/org/apache/catalina/startup/SimpleHttpClient.java
+++ b/test/org/apache/catalina/startup/SimpleHttpClient.java
@@ -31,6 +31,7 @@ import java.net.SocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Simple client for unit testing. It isn't robust, it isn't secure and
@@ -39,7 +40,7 @@ import java.util.List;
  */
 public abstract class SimpleHttpClient {
     public static final String TEMP_DIR =
-        System.getProperty("java.io.tmpdir");
+            System.getProperty("java.io.tmpdir");
 
     public static final String CRLF = "\r\n";
 
@@ -48,13 +49,32 @@ public abstract class SimpleHttpClient {
     public static final String REDIRECT_302 = "HTTP/1.1 302";
     public static final String FAIL_400 = "HTTP/1.1 400";
     public static final String FAIL_404 = "HTTP/1.1 404";
+    public static final String TIMEOUT_408 = "HTTP/1.1 408";
     public static final String FAIL_413 = "HTTP/1.1 413";
     public static final String FAIL_50X = "HTTP/1.1 50";
     public static final String FAIL_500 = "HTTP/1.1 500";
     public static final String FAIL_501 = "HTTP/1.1 501";
 
+    private static final String CONTENT_LENGTH_HEADER_PREFIX =
+            "Content-Length: ";
+
+    protected static final String SESSION_COOKIE_NAME = "JSESSIONID";
+    protected static final String SESSION_PARAMETER_NAME =
+            SESSION_COOKIE_NAME.toLowerCase(Locale.US);
+
+    private static final String COOKIE_HEADER_PREFIX = "Set-Cookie: ";
     private static final String SESSION_COOKIE_HEADER_PREFIX =
-        "Set-Cookie: JSESSIONID=";
+            COOKIE_HEADER_PREFIX + SESSION_COOKIE_NAME + "=";
+
+    private static final String REDIRECT_HEADER_PREFIX = "Location: ";
+    protected static final String SESSION_PATH_PARAMETER_PREFIX =
+            SESSION_PARAMETER_NAME + "=";
+    protected static final String SESSION_PATH_PARAMETER_TAILS = CRLF + ";?";
+
+    private static final String ELEMENT_HEAD = "<";
+    private static final String ELEMENT_TAIL = ">";
+    private static final String RESOURCE_TAG = "a";
+    private static final String LOGIN_TAG = "form";
 
     private Socket socket;
     private Writer writer;
@@ -63,12 +83,18 @@ public abstract class SimpleHttpClient {
 
     private String[] request;
     private boolean useContinue = false;
+    private boolean useCookies = true;
     private int requestPause = 1000;
 
     private String responseLine;
     private List<String> responseHeaders = new ArrayList<String>();
-    private String responseBody;
+    private String sessionId;
     private boolean useContentLength;
+    private int contentLength;
+    private String redirectUri;
+
+    private String responseBody;
+    private List<String> bodyUriElements = null;
 
     protected void setPort(int thePort) {
         port = thePort;
@@ -78,6 +104,9 @@ public abstract class SimpleHttpClient {
         request = theRequest;
     }
 
+    /*
+     * Expect the server to reply with 100 Continue interim response
+     */
     public void setUseContinue(boolean theUseContinueFlag) {
         useContinue = theUseContinueFlag;
     }
@@ -86,6 +115,14 @@ public abstract class SimpleHttpClient {
         return useContinue;
     }
 
+    public void setUseCookies(boolean theUseCookiesFlag) {
+        useCookies = theUseCookiesFlag;
+    }
+
+    public boolean getUseCookies() {
+        return useCookies;
+    }
+
     public void setRequestPause(int theRequestPause) {
         requestPause = theRequestPause;
     }
@@ -102,22 +139,39 @@ public abstract class SimpleHttpClient {
         return responseBody;
     }
 
+    /**
+     * Return opening tags of HTML elements that were extracted by the
+     * {@link #extractUriElements()} method.
+     *
+     * <p>
+     * Note, that {@link #extractUriElements()} method has to be called
+     * explicitly.
+     *
+     * @return List of HTML tags, accumulated by {@link #extractUriElements()}
+     *         method, or {@code null} if the method has not been called yet.
+     */
+    public List<String> getResponseBodyUriElements() {
+        return bodyUriElements;
+    }
+
     public void setUseContentLength(boolean b) {
         useContentLength = b;
     }
 
+    public void setSessionId(String theSessionId) {
+        sessionId = theSessionId;
+    }
+
     public String getSessionId() {
-        for (String header : responseHeaders) {
-            if (header.startsWith(SESSION_COOKIE_HEADER_PREFIX)) {
-                header = header.substring(SESSION_COOKIE_HEADER_PREFIX.length());
-                header = header.substring(0, header.indexOf(';'));
-                return header;
-            }
-        }
-        return null;
+        return sessionId;
+    }
+
+    public String getRedirectUri() {
+        return redirectUri;
     }
 
-    public void connect(int connectTimeout, int soTimeout) throws UnknownHostException, IOException {
+    public void connect(int connectTimeout, int soTimeout)
+           throws UnknownHostException, IOException {
         final String encoding = "ISO-8859-1";
         SocketAddress addr = new InetSocketAddress("localhost", port);
         socket = new Socket();
@@ -137,34 +191,43 @@ public abstract class SimpleHttpClient {
         processRequest(true);
     }
 
-    public void processRequest(boolean readBody) throws IOException, InterruptedException {
+    public void processRequest(boolean wantBody)
+            throws IOException, InterruptedException {
         sendRequest();
 
-        readResponse(readBody);
+        readResponse(wantBody);
 
     }
 
+    /*
+     * Send the component parts of the request
+     * (be tolerant and simply skip null entries)
+     */
     public void sendRequest() throws InterruptedException, IOException {
-        // Send the request
         boolean first = true;
         for (String requestPart : request) {
-            if (first) {
-                first = false;
-            } else {
-                Thread.sleep(requestPause);
+            if (requestPart != null) {
+                if (first) {
+                    first = false;
+                }
+                else {
+                    Thread.sleep(requestPause);
+                }
+                writer.write(requestPart);
+                writer.flush();
             }
-            writer.write(requestPart);
-            writer.flush();
         }
     }
 
-    public void readResponse(boolean readBody) throws IOException {
-        // Reset fields use to hold response
-        responseLine = null;
+    public void readResponse(boolean wantBody) throws IOException {
+        // clear any residual data before starting on this response
         responseHeaders.clear();
         responseBody = null;
+        if (bodyUriElements != null) {
+            bodyUriElements.clear();
+        }
 
-        // Read the response
+        // Read the response status line
         responseLine = readLine();
 
         // Is a 100 continue response expected?
@@ -179,35 +242,125 @@ public abstract class SimpleHttpClient {
             }
         }
 
-        // Put the headers into the map
+        // Put the headers into a map, and process interesting ones
+        processHeaders();
+
+        // Read the body, if requested and if one exists
+        processBody(wantBody);
+
+        if (isResponse408()) {
+            // the session has timed out
+            sessionId = null;
+        }
+    }
+
+    /*
+     * Accumulate the response headers into a map, and extract
+     * interesting details at the same time
+     */
+    private void processHeaders() throws IOException {
+        // Reset response fields
+        redirectUri = null;
+        contentLength = -1;
+
         String line = readLine();
-        int cl = -1;
-        while (line!=null && line.length() > 0) {
+        while ((line != null) && (line.length() > 0)) {
             responseHeaders.add(line);
-            line = readLine();
-            if (line != null && line.startsWith("Content-Length: ")) {
-                cl = Integer.parseInt(line.substring(16));
+            if (line.startsWith(CONTENT_LENGTH_HEADER_PREFIX)) {
+                contentLength = Integer.parseInt(line.substring(16));
             }
+            else if (line.startsWith(COOKIE_HEADER_PREFIX)) {
+                if (useCookies) {
+                    String temp = line.substring(
+                            SESSION_COOKIE_HEADER_PREFIX.length());
+                    temp = temp.substring(0, temp.indexOf(';'));
+                    setSessionId(temp);
+                }
+            }
+            else if (line.startsWith(REDIRECT_HEADER_PREFIX)) {
+                redirectUri = line.substring(REDIRECT_HEADER_PREFIX.length());
+            }
+            line = readLine();
         }
+    }
 
-        // Read the body, if any
+    /*
+     * Read the body of the server response. Save its contents and
+     * search it for uri-elements only if requested
+     */
+    private void processBody(boolean wantBody) throws IOException {
+        // Read the body, if one exists
         StringBuilder builder = new StringBuilder();
-        if (readBody) {
-            if (cl > -1 && useContentLength) {
-                char[] body = new char[cl];
+        if (wantBody) {
+            if (useContentLength && (contentLength > -1)) {
+                char[] body = new char[contentLength];
                 reader.read(body);
                 builder.append(body);
-            } else {
-                line = readLine();
-                while (line != null) {
+            }
+            else {
+                // not using content length, so just read it line by line
+                String line = null;
+                while ((line = readLine()) != null) {
                     builder.append(line);
-                    line = readLine();
                 }
             }
         }
         responseBody = builder.toString();
     }
 
+    /**
+     * Scan the response body for opening tags of certain HTML elements
+     * (<a>, <form>). If any are found, then accumulate them.
+     *
+     * <p>
+     * Note: This method has the following limitations: a) It assumes that the
+     * response is HTML. b) It searches for lowercase tags only.
+     *
+     * @see #getResponseBodyUriElements()
+     */
+    public void extractUriElements() {
+        bodyUriElements = new ArrayList<String>();
+        if (responseBody.length() > 0) {
+            int ix = 0;
+            while ((ix = extractUriElement(responseBody, ix, RESOURCE_TAG)) > 0){
+                // loop
+            }
+            ix = 0;
+            while ((ix = extractUriElement(responseBody, ix, LOGIN_TAG)) > 0){
+                // loop
+            }
+        }
+    }
+
+    /*
+     * Scan an html body for a given html uri element, starting from the
+     * given index into the source string. If any are found, simply
+     * accumulate them as literal strings, including angle brackets.
+     * note: nested elements will not be collected.
+     *
+     * @param body HTTP body of the response
+     * @param startIx offset into the body to resume the scan (for iteration)
+     * @param elementName to scan for (only one at a time)
+     * @returns the index into the body to continue the scan (for iteration)
+     */
+    private int extractUriElement(String body, int startIx, String elementName) {
+        String detector = ELEMENT_HEAD + elementName + " ";
+        int iStart = body.indexOf(detector, startIx);
+        if (iStart > -1) {
+            int iEnd = body.indexOf(ELEMENT_TAIL, iStart);
+            if (iEnd < 0) {
+                throw new IllegalArgumentException(
+                        "Response body check failure.\n"
+                        + "element [" + detector + "] is not terminated with ["
+                        + ELEMENT_TAIL + "]\nActual: [" + body + "]");
+            }
+            String element = body.substring(iStart, iEnd);
+            bodyUriElements.add(element);
+            iStart += element.length();
+        }
+        return iStart;
+    }
+
     public String readLine() throws IOException {
         return reader.readLine();
     }
@@ -253,6 +406,10 @@ public abstract class SimpleHttpClient {
         return getResponseLine().startsWith(FAIL_404);
     }
 
+    public boolean isResponse408() {
+        return getResponseLine().startsWith(TIMEOUT_408);
+    }
+
     public boolean isResponse413() {
         return getResponseLine().startsWith(FAIL_413);
     }
diff --git a/test/org/apache/catalina/startup/TestContextConfig.java b/test/org/apache/catalina/startup/TestContextConfig.java
index 0ddae4f..bbc3a21 100644
--- a/test/org/apache/catalina/startup/TestContextConfig.java
+++ b/test/org/apache/catalina/startup/TestContextConfig.java
@@ -29,6 +29,8 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import junit.framework.Assert;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -94,6 +96,26 @@ public class TestContextConfig extends TomcatBaseTest {
         assertTrue(bc.toString().contains("<p>OK</p>"));
     }
 
+    @Test
+    public void testBug53574() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp-3.0");
+        tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+
+        tomcat.start();
+
+        ByteChunk res = new ByteChunk();
+
+        int rc = getUrl("http://localhost:" + getPort() +
+                "/test/bug53574", res, null);
+
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+
+        String body = res.toString();
+        Assert.assertTrue(body.contains("OK"));
+    }
+
     private static class CustomDefaultServletSCI
             implements ServletContainerInitializer {
 
diff --git a/test/org/apache/catalina/startup/TestContextConfigAnnotation.java b/test/org/apache/catalina/startup/TestContextConfigAnnotation.java
index ad46607..666431d 100644
--- a/test/org/apache/catalina/startup/TestContextConfigAnnotation.java
+++ b/test/org/apache/catalina/startup/TestContextConfigAnnotation.java
@@ -49,7 +49,7 @@ import org.apache.catalina.deploy.WebXml;
  * fragment.
  *
  * @author Peter Rossbach
- * @version $Revision: 1237607 $
+ * @version $Revision: 1352803 $
  */
 public class TestContextConfigAnnotation {
 
@@ -60,7 +60,7 @@ public class TestContextConfigAnnotation {
         File pFile = paramClassResource(
                 "org/apache/catalina/startup/ParamServlet");
         assertTrue(pFile.exists());
-        config.processAnnotationsFile(pFile, webxml);
+        config.processAnnotationsFile(pFile, webxml, false);
         ServletDef servletDef = webxml.getServlets().get("param");
         assertNotNull(servletDef);
         assertEquals("Hello", servletDef.getParameterMap().get("foo"));
@@ -99,7 +99,7 @@ public class TestContextConfigAnnotation {
         File pFile = paramClassResource(
                 "org/apache/catalina/startup/ParamServlet");
         assertTrue(pFile.exists());
-        config.processAnnotationsFile(pFile, webxml);
+        config.processAnnotationsFile(pFile, webxml, false);
 
         assertEquals(servletDef, webxml.getServlets().get("param"));
 
@@ -126,12 +126,12 @@ public class TestContextConfigAnnotation {
         File pFile = paramClassResource(
                 "org/apache/catalina/startup/NoMappingParamServlet");
         assertTrue(pFile.exists());
-        config.processAnnotationsFile(pFile, webxml);
+        config.processAnnotationsFile(pFile, webxml, false);
         ServletDef servletDef = webxml.getServlets().get("param1");
         assertNull(servletDef);
 
         webxml.addServletMapping("/param", "param1");
-        config.processAnnotationsFile(pFile, webxml);
+        config.processAnnotationsFile(pFile, webxml, false);
         servletDef = webxml.getServlets().get("param1");
         assertNull(servletDef);
 
@@ -152,7 +152,7 @@ public class TestContextConfigAnnotation {
         File pFile = paramClassResource(
                 "org/apache/catalina/startup/NoMappingParamServlet");
         assertTrue(pFile.exists());
-        config.processAnnotationsFile(pFile, webxml);
+        config.processAnnotationsFile(pFile, webxml, false);
         assertEquals("tomcat", servletDef.getParameterMap().get("foo"));
         assertEquals("World!", servletDef.getParameterMap().get("bar"));
         ServletDef servletDef1 = webxml.getServlets().get("param1");
@@ -168,7 +168,7 @@ public class TestContextConfigAnnotation {
                 "org/apache/catalina/startup/DuplicateMappingParamServlet");
         assertTrue(pFile.exists());
         try {
-            config.processAnnotationsFile(pFile, webxml);
+            config.processAnnotationsFile(pFile, webxml, false);
             fail();
         } catch (IllegalArgumentException ex) {
             // ignore
@@ -183,10 +183,10 @@ public class TestContextConfigAnnotation {
         ContextConfig config = new ContextConfig();
         File sFile = paramClassResource(
                 "org/apache/catalina/startup/ParamServlet");
-        config.processAnnotationsFile(sFile, webxml);
+        config.processAnnotationsFile(sFile, webxml, false);
         File fFile = paramClassResource(
                 "org/apache/catalina/startup/ParamFilter");
-        config.processAnnotationsFile(fFile, webxml);
+        config.processAnnotationsFile(fFile, webxml, false);
         FilterDef fdef = webxml.getFilters().get("paramFilter");
         assertNotNull(fdef);
         assertEquals("Servlet says: ",fdef.getParameterMap().get("message"));
@@ -215,10 +215,10 @@ public class TestContextConfigAnnotation {
         ContextConfig config = new ContextConfig();
         File sFile = paramClassResource(
                 "org/apache/catalina/startup/ParamServlet");
-        config.processAnnotationsFile(sFile, webxml);
+        config.processAnnotationsFile(sFile, webxml, false);
         File fFile = paramClassResource(
                 "org/apache/catalina/startup/ParamFilter");
-        config.processAnnotationsFile(fFile, webxml);
+        config.processAnnotationsFile(fFile, webxml, false);
         FilterDef fdef = webxml.getFilters().get("paramFilter");
         assertNotNull(fdef);
         assertEquals(filterDef,fdef);
@@ -255,7 +255,7 @@ public class TestContextConfigAnnotation {
                 "org/apache/catalina/startup/DuplicateMappingParamFilter");
         assertTrue(pFile.exists());
         try {
-            config.processAnnotationsFile(pFile, webxml);
+            config.processAnnotationsFile(pFile, webxml, false);
             fail();
         } catch (IllegalArgumentException ex) {
             // ignore
@@ -297,13 +297,13 @@ public class TestContextConfigAnnotation {
         WebXml ignore = new WebXml();
         File file = paramClassResource(
                 "org/apache/catalina/startup/ParamServlet");
-        config.processAnnotationsFile(file, ignore);
+        config.processAnnotationsFile(file, ignore, false);
         file = paramClassResource("org/apache/catalina/startup/ParamFilter");
-        config.processAnnotationsFile(file, ignore);
+        config.processAnnotationsFile(file, ignore, false);
         file = paramClassResource("org/apache/catalina/startup/TesterServlet");
-        config.processAnnotationsFile(file, ignore);
+        config.processAnnotationsFile(file, ignore, false);
         file = paramClassResource("org/apache/catalina/startup/TestListener");
-        config.processAnnotationsFile(file, ignore);
+        config.processAnnotationsFile(file, ignore, false);
 
         // Check right number of classes were noted to be handled
         assertEquals(0, config.initializerClassMap.get(sciNone).size());
diff --git a/test/org/apache/catalina/startup/TomcatBaseTest.java b/test/org/apache/catalina/startup/TomcatBaseTest.java
index 33d5fd1..c0bc374 100644
--- a/test/org/apache/catalina/startup/TomcatBaseTest.java
+++ b/test/org/apache/catalina/startup/TomcatBaseTest.java
@@ -200,6 +200,11 @@ public abstract class TomcatBaseTest extends LoggingBaseTest {
         return getUrl(path, out, null, resHead);
     }
 
+    public static int headUrl(String path, ByteChunk out,
+            Map<String, List<String>> resHead) throws IOException {
+        return methodUrl(path, out, 1000000, null, resHead, "HEAD");
+    }
+
     public static int getUrl(String path, ByteChunk out,
             Map<String, List<String>> reqHead,
             Map<String, List<String>> resHead) throws IOException {
@@ -209,12 +214,20 @@ public abstract class TomcatBaseTest extends LoggingBaseTest {
     public static int getUrl(String path, ByteChunk out, int readTimeout,
             Map<String, List<String>> reqHead,
             Map<String, List<String>> resHead) throws IOException {
+        return methodUrl(path, out, readTimeout, reqHead, resHead, "GET");
+    }
+
+    public static int methodUrl(String path, ByteChunk out, int readTimeout,
+            Map<String, List<String>> reqHead,
+            Map<String, List<String>> resHead,
+            String method) throws IOException {
 
         URL url = new URL(path);
         HttpURLConnection connection =
             (HttpURLConnection) url.openConnection();
         connection.setUseCaches(false);
         connection.setReadTimeout(readTimeout);
+        connection.setRequestMethod(method);
         if (reqHead != null) {
             for (Map.Entry<String, List<String>> entry : reqHead.entrySet()) {
                 StringBuilder valueList = new StringBuilder();
diff --git a/test/org/apache/catalina/valves/TestAccessLogValve.java b/test/org/apache/catalina/valves/TestAccessLogValve.java
new file mode 100644
index 0000000..4047030
--- /dev/null
+++ b/test/org/apache/catalina/valves/TestAccessLogValve.java
@@ -0,0 +1,94 @@
+/*
+ * 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.valves;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestAccessLogValve {
+
+    // Note that there is a similar test:
+    // org.apache.juli.TestDateFormatCache.testBug54044()
+    @Test
+    public void testBug54044() throws Exception {
+
+        final int cacheSize = 10;
+
+        SimpleDateFormat sdf =
+                new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);
+        sdf.setTimeZone(TimeZone.getDefault());
+
+        AccessLogValve.DateFormatCache dfc =
+                new AccessLogValve.DateFormatCache(
+                        cacheSize, Locale.US, null);
+
+        // Create an array to hold the expected values
+        String[] expected = new String[cacheSize];
+
+        // Fill the cache & populate the expected values
+        for (int secs = 0; secs < (cacheSize); secs++) {
+            dfc.getFormat(secs * 1000);
+            expected[secs] = generateExpected(sdf, secs);
+        }
+        Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
+
+
+        // Cause the cache to roll-around by one and then confirm
+        dfc.getFormat(cacheSize * 1000);
+        expected[0] = generateExpected(sdf, cacheSize);
+        Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
+
+        // Jump 2 ahead and then confirm (skipped value should be null)
+        dfc.getFormat((cacheSize + 2)* 1000);
+        expected[1] = null;
+        expected[2] = generateExpected(sdf, cacheSize + 2);
+        Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
+
+        // Back 1 to fill in the gap
+        dfc.getFormat((cacheSize + 1)* 1000);
+        expected[1] = generateExpected(sdf, cacheSize + 1);
+        Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
+
+        // Return to 1 and confirm skipped value is null
+        dfc.getFormat(1 * 1000);
+        expected[1] = generateExpected(sdf, 1);
+        expected[2] = null;
+        Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
+
+        // Go back one further
+        dfc.getFormat(0);
+        expected[0] = generateExpected(sdf, 0);
+        Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
+
+        // Jump ahead far enough that the entire cache will need to be cleared
+        dfc.getFormat(42 * 1000);
+        for (int i = 0; i < cacheSize; i++) {
+            expected[i] = null;
+        }
+        expected[0] = generateExpected(sdf, 42);
+        Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
+    }
+
+    private String generateExpected(SimpleDateFormat sdf, long secs) {
+        return "[" + sdf.format(new Date(secs * 1000)) + " +0000]";
+    }
+}
diff --git a/test/org/apache/catalina/valves/TesterAccessLogValve.java b/test/org/apache/catalina/valves/TesterAccessLogValve.java
index a4ab7c5..9437c26 100644
--- a/test/org/apache/catalina/valves/TesterAccessLogValve.java
+++ b/test/org/apache/catalina/valves/TesterAccessLogValve.java
@@ -32,7 +32,7 @@ import org.apache.catalina.connector.Response;
 public class TesterAccessLogValve extends ValveBase implements AccessLog {
 
     // Timing tests need a small error margin to prevent failures
-    private static final long ERROR_MARGIN = 10;
+    private static final long ERROR_MARGIN = 100;
 
     private final List<Entry> entries = new ArrayList<Entry>();
 
diff --git a/test/org/apache/catalina/websocket/TestWebSocket.java b/test/org/apache/catalina/websocket/TestWebSocket.java
index ebb7a40..a07db54 100644
--- a/test/org/apache/catalina/websocket/TestWebSocket.java
+++ b/test/org/apache/catalina/websocket/TestWebSocket.java
@@ -36,6 +36,7 @@ import java.util.List;
 
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
+import javax.servlet.http.HttpServletRequest;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -296,7 +297,8 @@ public class TestWebSocket extends TomcatBaseTest {
         private static final long serialVersionUID = 1L;
 
         @Override
-        protected StreamInbound createWebSocketInbound(String subProtocol) {
+        protected StreamInbound createWebSocketInbound(String subProtocol,
+                HttpServletRequest request) {
             return new Bug53339WsInbound();
         }
     }
diff --git a/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java b/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java
index fe7d5e4..ffa6e7c 100644
--- a/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java
+++ b/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java
@@ -18,6 +18,7 @@ package org.apache.coyote.http11;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.CharBuffer;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -311,6 +312,68 @@ public class TestAbstractHttp11Processor extends TomcatBaseTest {
         assertEquals("OK", responseBody.toString());
     }
 
+    @Test
+    public void testBug53677a() throws Exception {
+        doTestBug53677(false);
+    }
+
+    @Test
+    public void testBug53677b() throws Exception {
+        doTestBug53677(true);
+    }
+
+    private void doTestBug53677(boolean flush) throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        // Must have a real docBase - just use temp
+        Context ctxt = tomcat.addContext("",
+                System.getProperty("java.io.tmpdir"));
+
+        Tomcat.addServlet(ctxt, "LargeHeaderServlet",
+                new LargeHeaderServlet(flush));
+        ctxt.addServletMapping("/test", "LargeHeaderServlet");
+
+        tomcat.start();
+
+        ByteChunk responseBody = new ByteChunk();
+        Map<String,List<String>> responseHeaders =
+                new HashMap<String,List<String>>();
+        int rc = getUrl("http://localhost:" + getPort() + "/test", responseBody,
+                responseHeaders);
+
+        assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, rc);
+        if (responseBody.getLength() > 0) {
+            // It will be >0 if the standard error page handlign has been
+            // triggered
+            assertFalse(responseBody.toString().contains("FAIL"));
+        }
+    }
+
+    private static final class LargeHeaderServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        boolean flush = false;
+
+        public LargeHeaderServlet(boolean flush) {
+            this.flush = flush;
+        }
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            String largeValue =
+                    CharBuffer.allocate(10000).toString().replace('\0', 'x');
+            resp.setHeader("x-Test", largeValue);
+            if (flush) {
+                resp.flushBuffer();
+            }
+            resp.setContentType("text/plain");
+            resp.getWriter().print("FAIL");
+        }
+
+    }
+
     // flushes with no content-length set
     // should result in chunking on HTTP 1.1
     private static final class NoContentLengthFlushingServlet
diff --git a/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java b/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java
index a57182e..a98700d 100644
--- a/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java
+++ b/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java
@@ -27,6 +27,8 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
@@ -38,8 +40,63 @@ import org.apache.catalina.startup.TomcatBaseTest;
 
 public class TestChunkedInputFilter extends TomcatBaseTest {
 
+    private static final String LF = "\n";
+
+    @Test
+    public void testChunkHeaderCRLF() throws Exception {
+        doTestChunkingCRLF(true, true, true, true, true, true);
+    }
+
+    @Test
+    public void testChunkHeaderLF() throws Exception {
+        doTestChunkingCRLF(false, true, true, true, true, false);
+    }
+
+    @Test
+    public void testChunkCRLF() throws Exception {
+        doTestChunkingCRLF(true, true, true, true, true, true);
+    }
+
+    @Test
+    public void testChunkLF() throws Exception {
+        doTestChunkingCRLF(true, false, true, true, true, false);
+    }
+
+    @Test
+    public void testFirstTrailingHeadersCRLF() throws Exception {
+        doTestChunkingCRLF(true, true, true, true, true, true);
+    }
+
+    @Test
+    public void testFirstTrailingHeadersLF() throws Exception {
+        doTestChunkingCRLF(true, true, false, true, true, true);
+    }
+
+    @Test
+    public void testSecondTrailingHeadersCRLF() throws Exception {
+        doTestChunkingCRLF(true, true, true, true, true, true);
+    }
+
+    @Test
+    public void testSecondTrailingHeadersLF() throws Exception {
+        doTestChunkingCRLF(true, true, true, false, true, true);
+    }
+
     @Test
-    public void testTrailingHeaders() throws Exception {
+    public void testEndCRLF() throws Exception {
+        doTestChunkingCRLF(true, true, true, true, true, true);
+    }
+
+    @Test
+    public void testEndLF() throws Exception {
+        doTestChunkingCRLF(true, true, true, true, false, false);
+    }
+
+    private void doTestChunkingCRLF(boolean chunkHeaderUsesCRLF,
+            boolean chunkUsesCRLF, boolean firstheaderUsesCRLF,
+            boolean secondheaderUsesCRLF, boolean endUsesCRLF,
+            boolean expectPass) throws Exception {
+
         // Setup Tomcat instance
         Tomcat tomcat = getTomcatInstance();
 
@@ -47,7 +104,8 @@ public class TestChunkedInputFilter extends TomcatBaseTest {
         Context ctx =
             tomcat.addContext("", System.getProperty("java.io.tmpdir"));
 
-        Tomcat.addServlet(ctx, "servlet", new EchoHeaderServlet());
+        EchoHeaderServlet servlet = new EchoHeaderServlet();
+        Tomcat.addServlet(ctx, "servlet", servlet);
         ctx.addServletMapping("/", "servlet");
 
         tomcat.start();
@@ -60,21 +118,45 @@ public class TestChunkedInputFilter extends TomcatBaseTest {
                     SimpleHttpClient.CRLF +
             "Connection: close" + SimpleHttpClient.CRLF +
             SimpleHttpClient.CRLF +
-            "3" + SimpleHttpClient.CRLF +
-            "a=0" + SimpleHttpClient.CRLF +
+            "3" + (chunkHeaderUsesCRLF ? SimpleHttpClient.CRLF : LF) +
+            "a=0" + (chunkUsesCRLF ? SimpleHttpClient.CRLF : LF) +
             "4" + SimpleHttpClient.CRLF +
             "&b=1" + SimpleHttpClient.CRLF +
             "0" + SimpleHttpClient.CRLF +
-            "x-trailer: Test", "TestTest0123456789abcdefghijABCDEFGHIJopqrstuvwxyz" + SimpleHttpClient.CRLF +
-            SimpleHttpClient.CRLF };
+            "x-trailer1: Test", "Value1" +
+            (firstheaderUsesCRLF ? SimpleHttpClient.CRLF : LF) +
+            "x-trailer2: TestValue2" +
+            (secondheaderUsesCRLF ? SimpleHttpClient.CRLF : LF) +
+            (endUsesCRLF ? SimpleHttpClient.CRLF : LF) };
 
         TrailerClient client =
                 new TrailerClient(tomcat.getConnector().getLocalPort());
         client.setRequest(request);
 
         client.connect();
-        client.processRequest();
-        assertEquals("null7TestTestTest0123456789abcdefghijABCDEFGHIJopqrstuvwxyz", client.getResponseBody());
+        Exception processException = null;
+        try {
+            client.processRequest();
+        } catch (Exception e) {
+            // Socket was probably closed before client had a chance to read
+            // response
+            processException = e;
+        }
+
+        if (expectPass) {
+            assertTrue(client.isResponse200());
+            assertEquals("nullnull7TestValue1TestValue2",
+                    client.getResponseBody());
+            assertNull(processException);
+            assertFalse(servlet.getExceptionDuringRead());
+        } else {
+            if (processException == null) {
+                assertTrue(client.getResponseLine(), client.isResponse500());
+            } else {
+                // Use fall-back for checking the error occurred
+                assertTrue(servlet.getExceptionDuringRead());
+            }
+        }
     }
 
     @Test
@@ -155,35 +237,49 @@ public class TestChunkedInputFilter extends TomcatBaseTest {
 
         client.connect();
         client.processRequest();
-        assertEquals("null7null", client.getResponseBody());
+        assertEquals("nullnull7nullnull", client.getResponseBody());
     }
 
     private static class EchoHeaderServlet extends HttpServlet {
         private static final long serialVersionUID = 1L;
 
+        private boolean exceptionDuringRead = false;
+
         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp)
                 throws ServletException, IOException {
             resp.setContentType("text/plain");
             PrintWriter pw = resp.getWriter();
-            // Header not visible yet, body not processed
-            String value = req.getHeader("x-trailer");
-            if (value == null) {
-                value = "null";
-            }
-            pw.write(value);
+            // Headers not visible yet, body not processed
+            dumpHeader("x-trailer1", req, pw);
+            dumpHeader("x-trailer2", req, pw);
 
             // Read the body - quick and dirty
             InputStream is = req.getInputStream();
             int count = 0;
-            while (is.read() > -1) {
-                count++;
+            try {
+                while (is.read() > -1) {
+                    count++;
+                }
+            } catch (IOException ioe) {
+                exceptionDuringRead = true;
+                throw ioe;
             }
 
             pw.write(Integer.valueOf(count).toString());
 
-            // Header should be visible now
-            value = req.getHeader("x-trailer");
+            // Headers should be visible now
+            dumpHeader("x-trailer1", req, pw);
+            dumpHeader("x-trailer2", req, pw);
+        }
+
+        public boolean getExceptionDuringRead() {
+            return exceptionDuringRead;
+        }
+
+        private void dumpHeader(String headerName, HttpServletRequest req,
+                PrintWriter pw) {
+            String value = req.getHeader(headerName);
             if (value == null) {
                 value = "null";
             }
diff --git a/test/org/apache/el/TestMethodExpressionImpl.java b/test/org/apache/el/TestMethodExpressionImpl.java
index feb2bcf..734634a 100644
--- a/test/org/apache/el/TestMethodExpressionImpl.java
+++ b/test/org/apache/el/TestMethodExpressionImpl.java
@@ -34,8 +34,11 @@ import org.apache.jasper.el.ELContextImpl;
 
 public class TestMethodExpressionImpl {
 
+    private static final String BUG53792 = "TEST_PASS";
+
     private ExpressionFactory factory;
     private ELContext context;
+    private TesterBeanB beanB;
 
     @Before
     public void setUp() {
@@ -57,7 +60,7 @@ public class TestMethodExpressionImpl {
         context.getVariableMapper().setVariable("beanAAA",
                 factory.createValueExpression(beanAAA, TesterBeanAAA.class));
 
-        TesterBeanB beanB = new TesterBeanB();
+        beanB = new TesterBeanB();
         beanB.setName("B");
         context.getVariableMapper().setVariable("beanB",
                 factory.createValueExpression(beanB, TesterBeanB.class));
@@ -430,4 +433,47 @@ public class TestMethodExpressionImpl {
         assertEquals(TesterEnum.APPLE, actual);
 
     }
+
+    @Test
+    public void testBug53792a() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "${beanA.setBean(beanB)}", null ,
+                new Class<?>[] { TesterBeanB.class });
+        me.invoke(context, null);
+        me = factory.createMethodExpression(context,
+                "${beanB.setName('" + BUG53792 + "')}", null ,
+                new Class<?>[] { TesterBeanB.class });
+        me.invoke(context, null);
+
+        ValueExpression ve = factory.createValueExpression(context,
+                "#{beanA.getBean().name}", java.lang.String.class);
+        String actual = (String) ve.getValue(context);
+        assertEquals(BUG53792, actual);
+    }
+
+    @Test
+    public void testBug53792b() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "${beanA.setBean(beanB)}", null ,
+                new Class<?>[] { TesterBeanB.class });
+        me.invoke(context, null);
+        me = factory.createMethodExpression(context,
+                "${beanB.setName('" + BUG53792 + "')}", null ,
+                new Class<?>[] { TesterBeanB.class });
+        me.invoke(context, null);
+
+        ValueExpression ve = factory.createValueExpression(context,
+                "#{beanA.getBean().name.length()}", java.lang.Integer.class);
+        Integer actual = (Integer) ve.getValue(context);
+        assertEquals(Integer.valueOf(BUG53792.length()), actual);
+    }
+
+
+    @Test
+    public void testBug53792c() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "#{beanB.sayHello().length()}", null, new Class<?>[] {});
+        Integer result = (Integer) me.invoke(context, null);
+        assertEquals(beanB.sayHello().length(), result.intValue());
+    }
 }
diff --git a/test/org/apache/jasper/compiler/TestCompiler.java b/test/org/apache/jasper/compiler/TestCompiler.java
index 3dd1a50..e794cee 100644
--- a/test/org/apache/jasper/compiler/TestCompiler.java
+++ b/test/org/apache/jasper/compiler/TestCompiler.java
@@ -168,6 +168,38 @@ public class TestCompiler extends TomcatBaseTest {
         tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
         tomcat.start();
 
+        ByteChunk res = getUrl("http://localhost:" + getPort() +
+                "/test/bug53257/foo%20bar.jsp");
+
+        // Check request completed
+        String result = res.toString();
+        assertEcho(result, "OK");
+    }
+
+    @Test
+    public void testBug53257g() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp-3.0");
+        tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+        tomcat.start();
+
+        ByteChunk res = getUrl("http://localhost:" + getPort() +
+                "/test/bug53257/foo%20bar/foobar.jsp");
+
+        // Check request completed
+        String result = res.toString();
+        assertEcho(result, "OK");
+    }
+
+    @Test
+    public void testBug53257z() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp-3.0");
+        tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+        tomcat.start();
+
         // Check that URL decoding is not done twice
         ByteChunk res = new ByteChunk();
         int rc = getUrl("http://localhost:" + getPort() +
diff --git a/test/org/apache/jasper/compiler/TestJspReader.java b/test/org/apache/jasper/compiler/TestJspReader.java
new file mode 100644
index 0000000..a60f2cd
--- /dev/null
+++ b/test/org/apache/jasper/compiler/TestJspReader.java
@@ -0,0 +1,44 @@
+/*
+ * 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.jasper.compiler;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+public class TestJspReader extends TomcatBaseTest {
+
+    @Test
+    public void testBug53986() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir =
+            new File("test/webapp-3.0");
+        tomcat.addWebapp(null, "", appDir.getAbsolutePath());
+
+        tomcat.start();
+
+        ByteChunk res = getUrl("http://localhost:" + getPort() +
+                "/bug53986.jsp");
+        Assert.assertTrue(res.toString().contains("OK"));
+    }
+}
diff --git a/test/org/apache/jasper/el/TestJasperELResolver.java b/test/org/apache/jasper/el/TestJasperELResolver.java
new file mode 100644
index 0000000..28a7208
--- /dev/null
+++ b/test/org/apache/jasper/el/TestJasperELResolver.java
@@ -0,0 +1,72 @@
+/*
+ * 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.jasper.el;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.el.ELResolver;
+import javax.servlet.jsp.el.ImplicitObjectELResolver;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestJasperELResolver {
+
+    @Test
+    public void testConstructorNone() throws Exception {
+        doTestConstructor(0);
+    }
+
+    @Test
+    public void testConstructorOne() throws Exception {
+        doTestConstructor(1);
+    }
+
+    @Test
+    public void testConstructorFive() throws Exception {
+        doTestConstructor(5);
+    }
+
+    private void doTestConstructor(int count) throws Exception {
+
+        List<ELResolver> list = new ArrayList<ELResolver>();
+        for (int i = 0; i < count; i++) {
+            list.add(new ImplicitObjectELResolver());
+        }
+
+        JasperELResolver resolver = new JasperELResolver(list);
+
+
+        Assert.assertEquals(Integer.valueOf(count),
+                getField("appResolversSize", resolver));
+        Assert.assertEquals(7 + count,
+                ((ELResolver[])getField("resolvers", resolver)).length);
+        Assert.assertEquals(Integer.valueOf(7 + count),
+                getField("size", resolver));
+
+    }
+
+    private static final Object getField(String name, Object target)
+            throws NoSuchFieldException, SecurityException,
+            IllegalArgumentException, IllegalAccessException {
+        Field field = target.getClass().getDeclaredField(name);
+        field.setAccessible(true);
+        return field.get(target);
+    }
+}
diff --git a/test/org/apache/jasper/runtime/TestPageContextImpl.java b/test/org/apache/jasper/runtime/TestPageContextImpl.java
new file mode 100644
index 0000000..444d195
--- /dev/null
+++ b/test/org/apache/jasper/runtime/TestPageContextImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jasper.runtime;
+
+import java.io.File;
+
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+public class TestPageContextImpl extends TomcatBaseTest {
+
+    @Test
+    public void testDoForward() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp-3.0");
+        tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+
+        tomcat.start();
+
+        ByteChunk res = new ByteChunk();
+
+        int rc = getUrl("http://localhost:" + getPort() +
+                "/test/bug53545.jsp", res, null);
+
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+
+        String body = res.toString();
+        Assert.assertTrue(body.contains("OK"));
+        Assert.assertFalse(body.contains("FAIL"));
+    }
+}
diff --git a/test/org/apache/jasper/runtime/TesterPageContextImpl.java b/test/org/apache/jasper/runtime/TesterPageContextImpl.java
new file mode 100644
index 0000000..4c6bd24
--- /dev/null
+++ b/test/org/apache/jasper/runtime/TesterPageContextImpl.java
@@ -0,0 +1,100 @@
+/*
+ * 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.jasper.runtime;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Performance tests for {@link PageContextImpl}.
+ */
+public class TesterPageContextImpl {
+
+    private static String[] bug53867TestData = new String[] {
+            "Hello World!",
+            "<meta http-equiv=\"Content-Language\">",
+            "This connection has limited network connectivity.",
+            "Please use this web page & to access file server resources." };
+
+    @Test
+    public void testBug53867() {
+        for (int i = 0; i < 10; i++) {
+            doTestBug53867();
+        }
+    }
+
+    private static void doTestBug53867() {
+        int count = 100000;
+
+        for (int j = 0; j < bug53867TestData.length; j++) {
+            Assert.assertEquals(doTestBug53867OldVersion(bug53867TestData[j]),
+                    PageContextImpl.XmlEscape(bug53867TestData[j]));
+        }
+
+        for (int i = 0; i < 100; i++) {
+            for (int j = 0; j < bug53867TestData.length; j++) {
+                doTestBug53867OldVersion(bug53867TestData[j]);
+            }
+        }
+        for (int i = 0; i < 100; i++) {
+            for (int j = 0; j < bug53867TestData.length; j++) {
+                PageContextImpl.XmlEscape(bug53867TestData[j]);
+            }
+        }
+
+        long start = System.currentTimeMillis();
+        for (int i = 0; i < count; i++) {
+            for (int j = 0; j < bug53867TestData.length; j++) {
+                doTestBug53867OldVersion(bug53867TestData[j]);
+            }
+        }
+        System.out.println(
+                "Old escape:" + (System.currentTimeMillis() - start));
+
+        start = System.currentTimeMillis();
+        for (int i = 0; i < count; i++) {
+            for (int j = 0; j < bug53867TestData.length; j++) {
+                PageContextImpl.XmlEscape(bug53867TestData[j]);
+            }
+        }
+        System.out.println(
+                "New escape:" + (System.currentTimeMillis() - start));
+    }
+
+    private static String doTestBug53867OldVersion(String s) {
+        if (s == null)
+            return null;
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '<') {
+                sb.append("<");
+            } else if (c == '>') {
+                sb.append(">");
+            } else if (c == '\'') {
+                sb.append("'"); // '
+            } else if (c == '&') {
+                sb.append("&");
+            } else if (c == '"') {
+                sb.append("""); // "
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+}
diff --git a/test/org/apache/juli/TestDateFormatCache.java b/test/org/apache/juli/TestDateFormatCache.java
new file mode 100644
index 0000000..8238be1
--- /dev/null
+++ b/test/org/apache/juli/TestDateFormatCache.java
@@ -0,0 +1,111 @@
+/*
+ * 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.juli;
+
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestDateFormatCache {
+
+    // Note that there is a similar test:
+    // org.apache.catalina.valves.TestAccessLogValve.testBug54044()
+    @Test
+    public void testBug54044() throws Exception {
+
+        final String timeFormat = "dd-MMM-yyyy HH:mm:ss";
+        final int cacheSize = 10;
+
+        SimpleDateFormat sdf = new SimpleDateFormat(timeFormat, Locale.US);
+        sdf.setTimeZone(TimeZone.getDefault());
+
+        DateFormatCache dfc = new DateFormatCache(cacheSize, timeFormat, null);
+
+        // Get dfc.cache.cache field
+        Object dfcCache;
+        Field dfcCacheArray;
+        {
+            Field dfcCacheField = dfc.getClass().getDeclaredField("cache");
+            dfcCacheField.setAccessible(true);
+            dfcCache = dfcCacheField.get(dfc);
+            dfcCacheArray = dfcCache.getClass().getDeclaredField("cache");
+            dfcCacheArray.setAccessible(true);
+        }
+
+        // Create an array to hold the expected values
+        String[] expected = new String[cacheSize];
+
+        // Fill the cache & populate the expected values
+        for (int secs = 0; secs < (cacheSize); secs++) {
+            dfc.getFormat(secs * 1000);
+            expected[secs] = generateExpected(sdf, secs);
+        }
+        Assert.assertArrayEquals(expected,
+                (String[]) dfcCacheArray.get(dfcCache));
+
+        // Cause the cache to roll-around by one and then confirm
+        dfc.getFormat(cacheSize * 1000);
+        expected[0] = generateExpected(sdf, cacheSize);
+        Assert.assertArrayEquals(expected,
+                (String[]) dfcCacheArray.get(dfcCache));
+
+        // Jump 2 ahead and then confirm (skipped value should be null)
+        dfc.getFormat((cacheSize + 2) * 1000);
+        expected[1] = null;
+        expected[2] = generateExpected(sdf, cacheSize + 2);
+        Assert.assertArrayEquals(expected,
+                (String[]) dfcCacheArray.get(dfcCache));
+
+        // Back 1 to fill in the gap
+        dfc.getFormat((cacheSize + 1) * 1000);
+        expected[1] = generateExpected(sdf, cacheSize + 1);
+        Assert.assertArrayEquals(expected,
+                (String[]) dfcCacheArray.get(dfcCache));
+
+        // Return to 1 and confirm skipped value is null
+        dfc.getFormat(1 * 1000);
+        expected[1] = generateExpected(sdf, 1);
+        expected[2] = null;
+        Assert.assertArrayEquals(expected,
+                (String[]) dfcCacheArray.get(dfcCache));
+
+        // Go back one further
+        dfc.getFormat(0);
+        expected[0] = generateExpected(sdf, 0);
+        Assert.assertArrayEquals(expected,
+                (String[]) dfcCacheArray.get(dfcCache));
+
+        // Jump ahead far enough that the entire cache will need to be cleared
+        dfc.getFormat(42 * 1000);
+        for (int i = 0; i < cacheSize; i++) {
+            expected[i] = null;
+        }
+        expected[0] = generateExpected(sdf, 42);
+        Assert.assertArrayEquals(expected,
+                (String[]) dfcCacheArray.get(dfcCache));
+    }
+
+    private String generateExpected(SimpleDateFormat sdf, long secs) {
+        return sdf.format(new Date(secs * 1000));
+    }
+
+}
diff --git a/test/org/apache/naming/resources/TestNamingContext.java b/test/org/apache/naming/resources/TestNamingContext.java
index 47681d2..ffe4f72 100644
--- a/test/org/apache/naming/resources/TestNamingContext.java
+++ b/test/org/apache/naming/resources/TestNamingContext.java
@@ -19,6 +19,7 @@ package org.apache.naming.resources;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 
 import javax.naming.Binding;
@@ -156,7 +157,13 @@ public class TestNamingContext extends TomcatBaseTest {
         byte[] buffer = new byte[4096];
         Resource res = (Resource)file;
 
-        int len = res.streamContent().read(buffer);
+        InputStream is = res.streamContent();
+        int len;
+        try {
+            len = is.read(buffer);
+        } finally {
+            is.close();
+        }
         String contents = new String(buffer, 0, len, "UTF-8");
 
         assertEquals(foxText, contents);
@@ -168,7 +175,12 @@ public class TestNamingContext extends TomcatBaseTest {
         Assert.assertTrue(file instanceof Resource);
 
         res = (Resource)file;
-        len = res.streamContent().read(buffer);
+        is = res.streamContent();
+        try {
+            len = is.read(buffer);
+        } finally {
+            is.close();
+        }
         contents = new String(buffer, 0, len, "UTF-8");
 
         assertEquals(loremIpsum, contents);
@@ -186,7 +198,12 @@ public class TestNamingContext extends TomcatBaseTest {
         Assert.assertTrue(file instanceof Resource);
 
         res = (Resource)file;
-        len = res.streamContent().read(buffer);
+        is = res.streamContent();
+        try {
+            len = is.read(buffer);
+        } finally {
+            is.close();
+        }
         contents = new String(buffer, 0, len, "UTF-8");
 
         assertEquals(foxText, contents);
@@ -198,7 +215,12 @@ public class TestNamingContext extends TomcatBaseTest {
         Assert.assertTrue(file instanceof Resource);
 
         res = (Resource)file;
-        len = res.streamContent().read(buffer);
+        is = res.streamContent();
+        try {
+            len = is.read(buffer);
+        } finally {
+            is.close();
+        }
         contents = new String(buffer, 0, len, "UTF-8");
 
         assertEquals(loremIpsum, contents);
@@ -458,4 +480,29 @@ public class TestNamingContext extends TomcatBaseTest {
             }
         }
     }
+
+    @Test
+    public void testBug53465() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        tomcat.enableNaming();
+
+        File appDir =
+            new File("test/webapp-3.0");
+        // app dir is relative to server home
+        org.apache.catalina.Context ctxt =
+                tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+
+        tomcat.start();
+
+        ByteChunk bc = new ByteChunk();
+        int rc = getUrl("http://localhost:" + getPort() +
+                "/test/bug53465.jsp", bc, null);
+
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+        Assert.assertTrue(bc.toString().contains("<p>10</p>"));
+
+        ContextEnvironment ce =
+                ctxt.getNamingResources().findEnvironment("bug53465");
+        Assert.assertEquals("Bug53465MappedName", ce.getProperty("mappedName"));
+    }
 }
diff --git a/test/org/apache/tomcat/unittest/tags/Bug53545.java b/test/org/apache/tomcat/unittest/tags/Bug53545.java
new file mode 100644
index 0000000..0361d0d
--- /dev/null
+++ b/test/org/apache/tomcat/unittest/tags/Bug53545.java
@@ -0,0 +1,23 @@
+/*
+ *  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.tomcat.unittest.tags;
+
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+public class Bug53545 extends BodyTagSupport {
+    private static final long serialVersionUID = 1L;
+}
diff --git a/test/org/apache/tomcat/util/buf/TestByteChunk.java b/test/org/apache/tomcat/util/buf/TestByteChunk.java
index 30a1b1c..4dc4b17 100644
--- a/test/org/apache/tomcat/util/buf/TestByteChunk.java
+++ b/test/org/apache/tomcat/util/buf/TestByteChunk.java
@@ -138,6 +138,7 @@ public class TestByteChunk {
     }
 
     @Test
+    @Deprecated
     public void testFindNotBytes() throws UnsupportedEncodingException {
         byte[] bytes = "Hello\u00a0world".getBytes("ISO-8859-1");
         final int len = bytes.length;
diff --git a/test/org/apache/tomcat/util/buf/TestHexUtils.java b/test/org/apache/tomcat/util/buf/TestHexUtils.java
new file mode 100644
index 0000000..6a42669
--- /dev/null
+++ b/test/org/apache/tomcat/util/buf/TestHexUtils.java
@@ -0,0 +1,42 @@
+/*
+ *  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.tomcat.util.buf;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Test cases for {@link HexUtils}.
+ */
+public class TestHexUtils {
+
+    @Test
+    public void testGetDec() {
+        assertEquals(0, HexUtils.getDec('0'));
+        assertEquals(9, HexUtils.getDec('9'));
+        assertEquals(10, HexUtils.getDec('a'));
+        assertEquals(15, HexUtils.getDec('f'));
+        assertEquals(10, HexUtils.getDec('A'));
+        assertEquals(15, HexUtils.getDec('F'));
+        assertEquals(-1, HexUtils.getDec(0));
+        assertEquals(-1, HexUtils.getDec('Z'));
+        assertEquals(-1, HexUtils.getDec(255));
+        assertEquals(-1, HexUtils.getDec(-60));
+    }
+}
diff --git a/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java b/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
new file mode 100644
index 0000000..8dfc62c
--- /dev/null
+++ b/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
@@ -0,0 +1,158 @@
+/*
+ *  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.tomcat.util.http.parser;
+
+import java.io.StringReader;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestAuthorizationDigest {
+
+    @Test
+    public void testBug54060a() throws Exception {
+        String header = "Digest username=\"mthornton\", " +
+                "realm=\"optrak.com\", " +
+                "nonce=\"1351427243671:c1d6360150712149bae931a3ed7cb498\", " +
+                "uri=\"/files/junk.txt\", " +
+                "response=\"c5c2410bfc46753e83a8f007888b0d2e\", " +
+                "opaque=\"DB85C1A73933A7EB586D10E4BF2924EF\", " +
+                "qop=auth, " +
+                "nc=00000001, " +
+                "cnonce=\"9926cb3c334ede11\"";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+        Assert.assertEquals("mthornton", result.get("username"));
+        Assert.assertEquals("optrak.com", result.get("realm"));
+        Assert.assertEquals("1351427243671:c1d6360150712149bae931a3ed7cb498",
+                result.get("nonce"));
+        Assert.assertEquals("/files/junk.txt", result.get("uri"));
+        Assert.assertEquals("c5c2410bfc46753e83a8f007888b0d2e",
+                result.get("response"));
+        Assert.assertEquals("DB85C1A73933A7EB586D10E4BF2924EF",
+                result.get("opaque"));
+        Assert.assertEquals("auth", result.get("qop"));
+        Assert.assertEquals("00000001", result.get("nc"));
+        Assert.assertEquals("9926cb3c334ede11", result.get("cnonce"));
+    }
+
+    @Test
+    public void testBug54060b() throws Exception {
+        String header = "Digest username=\"mthornton\", " +
+                "realm=\"optrak.com\", " +
+                "nonce=\"1351427480964:a01c16fed5168d72a2b5267395a2022e\", " +
+                "uri=\"/files\", " +
+                "algorithm=MD5, " +
+                "response=\"f310c44b87efc0bc0a7aab7096fd36b6\", " +
+                "opaque=\"DB85C1A73933A7EB586D10E4BF2924EF\", " +
+                "cnonce=\"MHg3ZjA3ZGMwMTUwMTA6NzI2OToxMzUxNDI3NDgw\", " +
+                "nc=00000001, " +
+                "qop=auth";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+        Assert.assertEquals("mthornton", result.get("username"));
+        Assert.assertEquals("optrak.com", result.get("realm"));
+        Assert.assertEquals("1351427480964:a01c16fed5168d72a2b5267395a2022e",
+                result.get("nonce"));
+        Assert.assertEquals("/files", result.get("uri"));
+        Assert.assertEquals("MD5", result.get("algorithm"));
+        Assert.assertEquals("f310c44b87efc0bc0a7aab7096fd36b6",
+                result.get("response"));
+        Assert.assertEquals("DB85C1A73933A7EB586D10E4BF2924EF",
+                result.get("opaque"));
+        Assert.assertEquals("MHg3ZjA3ZGMwMTUwMTA6NzI2OToxMzUxNDI3NDgw",
+                result.get("cnonce"));
+        Assert.assertEquals("00000001", result.get("nc"));
+        Assert.assertEquals("auth", result.get("qop"));
+    }
+
+    @Test
+    public void testBug54060c() throws Exception {
+        String header = "Digest username=\"mthornton\", qop=auth";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+        Assert.assertEquals("mthornton", result.get("username"));
+        Assert.assertEquals("auth", result.get("qop"));
+    }
+
+    @Test
+    public void testBug54060d() throws Exception {
+        String header = "Digest username=\"mthornton\"," +
+                "qop=auth," +
+                "cnonce=\"9926cb3c334ede11\"";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+        Assert.assertEquals("mthornton", result.get("username"));
+        Assert.assertEquals("auth", result.get("qop"));
+        Assert.assertEquals("9926cb3c334ede11", result.get("cnonce"));
+    }
+
+    @Test
+    public void testEndWithLhex() throws Exception {
+        String header = "Digest nc=00000001";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+        Assert.assertEquals("00000001", result.get("nc"));
+    }
+
+    @Test
+    public void testUnclosedQuotedString1() throws Exception {
+        String header = "Digest username=\"test";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+        Assert.assertNull(result);
+    }
+
+    @Test
+    public void testUnclosedQuotedString2() throws Exception {
+        String header = "Digest username=\"test\\";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+        Assert.assertNull(result);
+    }
+
+    @Test
+    public void testNonTokenDirective() throws Exception {
+        String header = "Digest user{name=\"test\"";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+        Assert.assertNull(result);
+    }
+
+}
diff --git a/test/org/apache/tomcat/util/http/parser/TestMediaType.java b/test/org/apache/tomcat/util/http/parser/TestMediaType.java
index d80cee6..f863648 100644
--- a/test/org/apache/tomcat/util/http/parser/TestMediaType.java
+++ b/test/org/apache/tomcat/util/http/parser/TestMediaType.java
@@ -16,8 +16,11 @@
  */
 package org.apache.tomcat.util.http.parser;
 
+import java.io.IOException;
 import java.io.StringReader;
 
+import junit.framework.Assert;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -60,93 +63,90 @@ public class TestMediaType {
 
 
     @Test
-    public void testSimple() throws ParseException {
+    public void testSimple() throws IOException {
         doTest();
     }
 
 
     @Test
-    public void testSimpleWithToken() throws ParseException {
+    public void testSimpleWithToken() throws IOException {
         doTest(PARAM_TOKEN);
     }
 
 
     @Test
-    public void testSimpleWithQuotedString() throws ParseException {
+    public void testSimpleWithQuotedString() throws IOException {
         doTest(PARAM_QUOTED);
     }
 
 
     @Test
-    public void testSimpleWithEmptyQuotedString() throws ParseException {
+    public void testSimpleWithEmptyQuotedString() throws IOException {
         doTest(PARAM_EMPTY_QUOTED);
     }
 
 
     @Test
-    public void testSimpleWithComplesQuotedString() throws ParseException {
+    public void testSimpleWithComplesQuotedString() throws IOException {
         doTest(PARAM_COMPLEX_QUOTED);
     }
 
 
     @Test
-    public void testSimpleWithCharset() throws ParseException {
+    public void testSimpleWithCharset() throws IOException {
         doTest(PARAM_CHARSET);
     }
 
 
     @Test
-    public void testSimpleWithCharsetWhitespaceBefore() throws ParseException {
+    public void testSimpleWithCharsetWhitespaceBefore() throws IOException {
         doTest(PARAM_WS_CHARSET);
     }
 
 
     @Test
-    public void testSimpleWithCharsetWhitespaceAfter() throws ParseException {
+    public void testSimpleWithCharsetWhitespaceAfter() throws IOException {
         doTest(PARAM_CHARSET_WS);
     }
 
 
     @Test
-    public void testSimpleWithCharsetQuoted() throws ParseException {
+    public void testSimpleWithCharsetQuoted() throws IOException {
         doTest(PARAM_CHARSET_QUOTED);
     }
 
 
     @Test
-    public void testSimpleWithAll() throws ParseException {
+    public void testSimpleWithAll() throws IOException {
         doTest(PARAM_COMPLEX_QUOTED, PARAM_EMPTY_QUOTED, PARAM_QUOTED,
                 PARAM_TOKEN, PARAM_CHARSET);
     }
 
 
     @Test
-    public void testCharset() throws ParseException {
+    public void testCharset() throws IOException {
         StringBuilder sb = new StringBuilder();
         sb.append(TYPES);
         sb.append(PARAM_CHARSET);
         sb.append(PARAM_TOKEN);
 
         StringReader sr = new StringReader(sb.toString());
-        HttpParser hp = new HttpParser(sr);
-        AstMediaType m = hp.MediaType();
+        MediaType m = HttpParser.parseMediaType(sr);
 
-        assertEquals(sb.toString().replaceAll(" ", ""), m.toString());
+        assertEquals("foo/bar; charset=UTF-8; a=b", m.toString());
         assertEquals(CHARSET, m.getCharset());
-        assertEquals(TYPES.replaceAll(" ", "") + PARAM_TOKEN,
-                m.toStringNoCharset());
+        assertEquals("foo/bar; a=b", m.toStringNoCharset());
     }
 
 
     @Test
-    public void testCharsetQuoted() throws ParseException {
+    public void testCharsetQuoted() throws IOException {
         StringBuilder sb = new StringBuilder();
         sb.append(TYPES);
         sb.append(PARAM_CHARSET_QUOTED);
 
         StringReader sr = new StringReader(sb.toString());
-        HttpParser hp = new HttpParser(sr);
-        AstMediaType m = hp.MediaType();
+        MediaType m = HttpParser.parseMediaType(sr);
 
         assertEquals(CHARSET_WS, m.getCharset());
         assertEquals(TYPES.replaceAll(" ", ""),
@@ -155,88 +155,59 @@ public class TestMediaType {
 
 
     @Test
-    public void testBug52811() throws ParseException {
+    public void testBug52811() throws IOException {
         String input = "multipart/related;boundary=1_4F50BD36_CDF8C28;" +
                 "Start=\"<31671603.smil>\";" +
                 "Type=\"application/smil;charset=UTF-8\"";
 
         StringReader sr = new StringReader(input);
-        HttpParser hp = new HttpParser(sr);
-        AstMediaType m = hp.MediaType();
-
-        assertTrue(m.children.length == 5);
+        MediaType m = HttpParser.parseMediaType(sr);
 
         // Check the types
-        assertTrue(m.children[0] instanceof AstType);
-        assertTrue(m.children[1] instanceof AstSubType);
-        assertEquals("multipart", m.children[0].toString());
-        assertEquals("related", m.children[1].toString());
+        assertEquals("multipart", m.getType());
+        assertEquals("related", m.getSubtype());
 
         // Check the parameters
-        AstParameter p = (AstParameter) m.children[2];
-        assertTrue(p.children.length == 2);
-        assertTrue(p.children[0] instanceof AstAttribute);
-        assertTrue(p.children[1] instanceof AstValue);
-        assertEquals("boundary", p.children[0].toString());
-        assertEquals("1_4F50BD36_CDF8C28", p.children[1].toString());
-
-        p = (AstParameter) m.children[3];
-        assertTrue(p.children.length == 2);
-        assertTrue(p.children[0] instanceof AstAttribute);
-        assertTrue(p.children[1] instanceof AstValue);
-        assertEquals("Start", p.children[0].toString());
-        assertEquals("\"<31671603.smil>\"", p.children[1].toString());
-
-        p = (AstParameter) m.children[4];
-        assertTrue(p.children.length == 2);
-        assertTrue(p.children[0] instanceof AstAttribute);
-        assertTrue(p.children[1] instanceof AstValue);
-        assertEquals("Type", p.children[0].toString());
+        assertTrue(m.getParameterCount() == 3);
+
+        assertEquals("1_4F50BD36_CDF8C28", m.getParameterValue("boundary"));
+        assertEquals("\"<31671603.smil>\"", m.getParameterValue("Start"));
         assertEquals("\"application/smil;charset=UTF-8\"",
-                p.children[1].toString());
+                m.getParameterValue("Type"));
 
-        assertEquals(input, m.toString());
-        assertEquals(input, m.toStringNoCharset());
+        String expected = "multipart/related; boundary=1_4F50BD36_CDF8C28; " +
+                "start=\"<31671603.smil>\"; " +
+                "type=\"application/smil;charset=UTF-8\"";
+        assertEquals(expected, m.toString());
+        assertEquals(expected, m.toStringNoCharset());
         assertNull(m.getCharset());
     }
 
 
     @Test
-    public void testBug53353() throws ParseException {
+    public void testBug53353() throws IOException {
         String input = "text/html; UTF-8;charset=UTF-8";
 
         StringReader sr = new StringReader(input);
-        HttpParser hp = new HttpParser(sr);
-        AstMediaType m = hp.MediaType();
-
-        assertTrue(m.children.length == 4);
+        MediaType m = HttpParser.parseMediaType(sr);
 
         // Check the types
-        assertTrue(m.children[0] instanceof AstType);
-        assertTrue(m.children[1] instanceof AstSubType);
-        assertEquals("text", m.children[0].toString());
-        assertEquals("html", m.children[1].toString());
+        assertEquals("text", m.getType());
+        assertEquals("html", m.getSubtype());
 
         // Check the parameters
-        AstParameter p = (AstParameter) m.children[2];
-        assertTrue(p.children.length == 1);
-        assertTrue(p.children[0] instanceof AstAttribute);
-        assertEquals("UTF-8", p.children[0].toString());
-
-        p = (AstParameter) m.children[3];
-        assertTrue(p.children.length == 2);
-        assertTrue(p.children[0] instanceof AstAttribute);
-        assertTrue(p.children[1] instanceof AstValue);
-        assertEquals("charset", p.children[0].toString());
-        assertEquals("UTF-8", p.children[1].toString());
+        assertTrue(m.getParameterCount() == 2);
+
+        assertEquals("", m.getParameterValue("UTF-8"));
+        assertEquals("UTF-8", m.getCharset());
 
         // Note: Invalid input is filtered out
-        assertEquals("text/html;charset=UTF-8", m.toString());
+        assertEquals("text/html; charset=UTF-8", m.toString());
         assertEquals("UTF-8", m.getCharset());
     }
 
 
-    private void doTest(Parameter... parameters) throws ParseException {
+    private void doTest(Parameter... parameters) throws IOException {
         StringBuilder sb = new StringBuilder();
         sb.append(TYPES);
         for (Parameter p : parameters) {
@@ -244,27 +215,19 @@ public class TestMediaType {
         }
 
         StringReader sr = new StringReader(sb.toString());
-        HttpParser hp = new HttpParser(sr);
-        AstMediaType m = hp.MediaType();
+        MediaType m = HttpParser.parseMediaType(sr);
 
-        // Check all expected children are present
-        assertTrue(m.children.length == 2 + parameters.length);
+        // Check all expected parameters are present
+        assertTrue(m.getParameterCount() == parameters.length);
 
         // Check the types
-        assertTrue(m.children[0] instanceof AstType);
-        assertTrue(m.children[1] instanceof AstSubType);
-        assertEquals(TYPE.trim(), m.children[0].toString());
-        assertEquals(SUBTYPE.trim(), m.children[1].toString());
+        assertEquals(TYPE.trim(), m.getType());
+        assertEquals(SUBTYPE.trim(), m.getSubtype());
 
         // Check the parameters
         for (int i = 0; i <  parameters.length; i++) {
-            assertTrue(m.children[i + 2] instanceof AstParameter);
-            AstParameter p = (AstParameter) m.children[i + 2];
-            assertTrue(p.children.length == 2);
-            assertTrue(p.children[0] instanceof AstAttribute);
-            assertTrue(p.children[1] instanceof AstValue);
-            assertEquals(parameters[i].getName().trim(), p.children[0].toString());
-            assertEquals(parameters[i].getValue().trim(), p.children[1].toString());
+            assertEquals(parameters[i].getValue().trim(),
+                    m.getParameterValue(parameters[i].getName().trim()));
         }
     }
 
@@ -296,4 +259,15 @@ public class TestMediaType {
             return sb.toString();
         }
     }
+
+    @Test
+    public void testCase() throws Exception {
+        StringReader sr = new StringReader("type/sub-type;a=1;B=2");
+        MediaType m = HttpParser.parseMediaType(sr);
+
+        Assert.assertEquals("1", m.getParameterValue("A"));
+        Assert.assertEquals("1", m.getParameterValue("a"));
+        Assert.assertEquals("2", m.getParameterValue("B"));
+        Assert.assertEquals("2", m.getParameterValue("b"));
+    }
 }
diff --git a/test/webapp-3.0-fragments/WEB-INF/lib/resources2.jar b/test/webapp-3.0-fragments/WEB-INF/lib/resources2.jar
index f976303..57e8424 100644
Binary files a/test/webapp-3.0-fragments/WEB-INF/lib/resources2.jar and b/test/webapp-3.0-fragments/WEB-INF/lib/resources2.jar differ
diff --git a/test/webapp-3.0/WEB-INF/bug53545.tld b/test/webapp-3.0/WEB-INF/bug53545.tld
new file mode 100644
index 0000000..4acfa02
--- /dev/null
+++ b/test/webapp-3.0/WEB-INF/bug53545.tld
@@ -0,0 +1,12 @@
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    <tlib-version>1.0</tlib-version>
+    <short-name>bug53545</short-name>
+    <tag>
+      <name>test</name>
+      <tag-class>org.apache.tomcat.unittest.tags.Bug53545</tag-class>
+      <body-content>scriptless</body-content>
+    </tag>
+</taglib>
\ No newline at end of file
diff --git a/test/webapp-3.0-fragments/bug51396.jsp b/test/webapp-3.0/WEB-INF/jsp/bug53574.jsp
similarity index 100%
copy from test/webapp-3.0-fragments/bug51396.jsp
copy to test/webapp-3.0/WEB-INF/jsp/bug53574.jsp
diff --git a/test/webapp-3.0/WEB-INF/web.xml b/test/webapp-3.0/WEB-INF/web.xml
index 9d8f008..64b9aa5 100644
--- a/test/webapp-3.0/WEB-INF/web.xml
+++ b/test/webapp-3.0/WEB-INF/web.xml
@@ -113,7 +113,25 @@
     <url-pattern>/testStandardWrapper/securityAnnotationsMetaDataPriority</url-pattern>
   </servlet-mapping>
 
+  <servlet>
+    <servlet-name>Bug53574</servlet-name>
+    <jsp-file>/WEB-INF/jsp/bug53574.jsp</jsp-file>
+  </servlet>
+  <servlet-mapping>
+    <servlet-name>Bug53574</servlet-name>
+    <url-pattern>/bug53574</url-pattern>
+  </servlet-mapping>
+
   <login-config>
     <auth-method>BASIC</auth-method>
   </login-config>
+
+  <env-entry>
+    <description>Resource for testing bug 53465</description>
+    <env-entry-name>bug53465</env-entry-name>
+    <env-entry-value>10</env-entry-value>
+    <env-entry-type>java.lang.Integer</env-entry-type>
+    <mapped-name>Bug53465MappedName</mapped-name>
+  </env-entry>
+
 </web-app>
\ No newline at end of file
diff --git a/test/webapp-3.0-fragments/bug51396.jsp b/test/webapp-3.0/bug53257/foo bar.jsp
similarity index 100%
copy from test/webapp-3.0-fragments/bug51396.jsp
copy to test/webapp-3.0/bug53257/foo bar.jsp
diff --git a/test/webapp-3.0/bug53257/foo#bar.txt b/test/webapp-3.0/bug53257/foo bar.txt
similarity index 100%
copy from test/webapp-3.0/bug53257/foo#bar.txt
copy to test/webapp-3.0/bug53257/foo bar.txt
diff --git a/test/webapp-3.0-fragments/bug51396.jsp b/test/webapp-3.0/bug53257/foo bar/foobar.jsp
similarity index 100%
copy from test/webapp-3.0-fragments/bug51396.jsp
copy to test/webapp-3.0/bug53257/foo bar/foobar.jsp
diff --git a/test/webapp-3.0/bug53257/foo#bar.txt b/test/webapp-3.0/bug53257/foo bar/foobar.txt
similarity index 100%
copy from test/webapp-3.0/bug53257/foo#bar.txt
copy to test/webapp-3.0/bug53257/foo bar/foobar.txt
diff --git a/test/webapp-3.0/bug53257/index.jsp b/test/webapp-3.0/bug53257/index.jsp
index 17ccebe..aa1f9dc 100644
--- a/test/webapp-3.0/bug53257/index.jsp
+++ b/test/webapp-3.0/bug53257/index.jsp
@@ -17,7 +17,8 @@
 <%@page contentType="text/plain; charset=UTF-8"
 %><%@page import="java.net.URL,java.net.URLConnection"%><%
     String[] testFiles = new String[] {"foo;bar.txt", "foo&bar.txt",
-            "foo#bar.txt", "foo%bar.txt", "foo+bar.txt"};
+            "foo#bar.txt", "foo%bar.txt", "foo+bar.txt", "foo bar.txt",
+            "foo bar/foobar.txt"};
     for (String testFile : testFiles) {
         URL url = application.getResource("/bug53257/" + testFile);
         if (url == null) {
diff --git a/test/webapp-3.0/bug53465.jsp b/test/webapp-3.0/bug53465.jsp
new file mode 100644
index 0000000..cb21f8b
--- /dev/null
+++ b/test/webapp-3.0/bug53465.jsp
@@ -0,0 +1,29 @@
+<%--
+ 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.
+--%>
+<%@ page import="javax.naming.Context" %>
+<%@ page import="javax.naming.InitialContext" %>
+<head>
+  <body>
+    <%
+      Context initCtx = new InitialContext();
+      Context envCtx = (Context) initCtx.lookup("java:comp/env");
+      Integer test = (Integer) envCtx.lookup("bug53465");
+
+      out.print("<p>" + test.intValue() + "</p>");
+    %>
+  </body>
+</head>
diff --git a/test/webapp-3.0/bug53467].jsp b/test/webapp-3.0/bug53467].jsp
new file mode 100644
index 0000000..102dcc3
--- /dev/null
+++ b/test/webapp-3.0/bug53467].jsp
@@ -0,0 +1,21 @@
+<%--
+ 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.
+--%>
+<head>
+  <body>
+    <p>OK</p>
+  </body>
+</head>
diff --git a/test/webapp-3.0/bug53545.html b/test/webapp-3.0/bug53545.html
new file mode 100644
index 0000000..35b67d7
--- /dev/null
+++ b/test/webapp-3.0/bug53545.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <p>OK</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/test/webapp-3.0/bug53545.jsp b/test/webapp-3.0/bug53545.jsp
new file mode 100644
index 0000000..1170a1f
--- /dev/null
+++ b/test/webapp-3.0/bug53545.jsp
@@ -0,0 +1,34 @@
+<%--
+ 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.
+--%>
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+         pageEncoding="ISO-8859-1"%>
+<%@ taglib prefix="bug53545" uri="/WEB-INF/bug53545.tld" %>
+<html>
+  <body>
+    <p>FAIL</p>
+    <bug53545:test>
+      <p>FAIL</p>
+      <bug53545:test>
+        <p>FAIL</p>
+        <jsp:forward page="bug53545.html"/>
+        <p>FAIL</p>
+      </bug53545:test>
+      <p>FAIL</p>
+    </bug53545:test>
+    <p>FAIL</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/test/webapp-3.0/bug53986.jsp b/test/webapp-3.0/bug53986.jsp
new file mode 100644
index 0000000..b8664fe
--- /dev/null
+++ b/test/webapp-3.0/bug53986.jsp
@@ -0,0 +1,22 @@
+<%--
+ 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.
+--%>
+<%--- Test comment ---%>
+<html>
+  <body>
+    <p>OK</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/webapps/docs/building.xml b/webapps/docs/building.xml
index f13ed9f..8a5fc81 100644
--- a/webapps/docs/building.xml
+++ b/webapps/docs/building.xml
@@ -42,12 +42,12 @@ Tomcat. The following is a step by step guide.
 
 </section>
 
-<section name="Download a Java Development Kit (JDK) 1.6 or later">
+<section name="Download a Java Development Kit (JDK) version 6">
 
 <p>
-Tomcat requires a JDK (version 1.6 or later) to be installed.
-<br/>The Sun JDK can be downloaded
-<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">here</a>.
+Building Apache Tomcat requires a JDK (version 6) to be installed. You can download one from<br />
+<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">http://www.oracle.com/technetwork/java/javase/downloads/index.html</a><br/>
+or from another JDK vendor.
 </p>
 
 <p>
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 718620c..3e2cab9 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -53,7 +53,748 @@
   They eventually become mixed with the numbered issues. (I.e., numbered
   issues to not "pop up" wrt. others).
 -->
-<section name="Tomcat 7.0.28 (markt)">
+<section name="Tomcat 7.0.33 (markt)">
+  <subsection name="Catalina">
+    <changelog>
+      <add>
+        <bug>53960</bug>, <bug>54115</bug>: Extensions to HttpClient test
+        helper class. Patches by Brian Burch. (markt/kkolinko)
+      </add>
+      <fix>
+        <bug>53993</bug>: Avoid a possible NPE in the AccessLogValve when the
+        session ID is logged and a session is invalidated. (markt)
+      </fix>
+      <fix>
+        Add support for LAST_ACCESS_AT_START system property to
+        PersistentManager. (kfujino)
+      </fix>
+      <add>
+        Update MIME type mapping with additional / updated mime.types from the
+        Apache web server. (markt)
+      </add>
+      <fix>
+        <bug>54007</bug>: Fix a memory leak that prevented deletion of a
+        context.xml file associated with a Context that had failed to deploy.
+        Also fix the problems uncovered with undeploying such a Context once the
+        leak had been fixed and the file could be deleted. (markt)
+      </fix>
+      <fix>
+        <bug>54044</bug>: Correct bug in timestamp cache used by logging
+        (including the access log valve) that meant entries could be made with
+        an earlier timestamp than the true timestamp. (markt) 
+      </fix>
+      <fix>
+        <bug>54054</bug>: Do not share shell environment variables between
+        multiple instances of the CGI servlet. (markt)
+      </fix>
+      <fix>
+        <bug>54060</bug>: Use a simple parser rather than a regular expression
+        to parse HTTP Digest authentication headers so the header is correctly
+        parsed. The new approach is also faster and generates less garbage.
+        (markt)
+      </fix>
+      <fix>
+        <bug>54068</bug>: Rewrite the web fragment ordering algorithm to resolve
+        multiple issues that resulted in incorrect ordering or failure to find
+        a correct, valid order. (markt)
+      </fix>
+      <update>
+        The HTTP header parser added to address <bug>52811</bug> has been
+        removed and replaced with the light-weight HTTP header parser created to
+        address <bug>54060</bug>. The new parser includes a work-around for a
+        bug in the Adobe Acrobat Reader 9.x plug-in for Microsoft Internet
+        Explorer that was identified when the old parser was introduced
+        (<bug>53814</bug>).  
+      </update>
+      <fix>
+        <bug>54076</bug>: Add an alternative work-around for clients that use
+        SPNEGO authentication and expect the authenticated user to be cached
+        per connection (Tomcat only does this if an HTTP session is available).
+        (markt) 
+      </fix>
+      <fix>
+        <bug>54087</bug>: Correctly handle (ignore) invalid If-Modified-Since
+        header rather than throwing an exception. (markt)
+      </fix>
+      <fix>
+        <bug>54096</bug>: In web.xml, <env-entry> should accept any type
+        that has a constructor that takes a single String or char. (markt)
+      </fix>
+      <add>
+        <bug>54127</bug>: Add support for sending a WebSocket Ping. Patch
+        provided by Sean Winterberger. (markt)
+      </add>
+      <fix>
+        In FormAuthenticator: If it is configured to change Session IDs,
+        do the change before displaying the login form. (kkolinko)
+      </fix>
+      <fix>
+        Ensure <code>AsyncListener.timeout()</code> and
+        <code>AsyncListener.complete()</code> are called with the correct
+        thread context class loader. (fhanik)
+      </fix>
+      <fix>
+        <bug>54123</bug>: If an asynchronous request times out without any
+        <code>AsyncListener</code>s defined, a 500 error will be triggered.
+        (markt)
+      </fix>
+      <fix>
+        <bug>54124</bug>: Correct provided value of request attribute
+        <code>javax.servlet.async.request_uri</code> and add missing request
+        attribute <code>javax.servlet.async.path_info</code>. (markt)
+      </fix>
+      <add>
+        Add <code>denyStatus</code> initialization parameter to
+        <code>CsrfPreventionFilter</code>, allowing to customize the HTTP
+        status code used for denied requests. (kkolinko)
+      </add>
+      <fix>
+        <bug>54141</bug>: Increase the permitted number of nested Realm levels
+        from 2 to 3 by default and make the limit configurable via a system
+        property. (markt)
+      </fix>
+      <fix>
+        Revert occasional API change in <code>BaseDirContext</code> class that
+        was done in 7.0.32. Methods should not be <code>final</code>. (kkolinko)
+      </fix>
+      <fix>
+        Prevent failures in the AccessLogValve when running under a
+        SecurityManager and the first request received is an asynchronous one.
+        (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Correct an issue that prevented WebSockets from being used over SSL when
+        using the HTTP NIO connector. (markt)
+      </fix>
+      <fix>
+       <bug>54022</bug>: Ensure the Comet END event is triggered on client
+       disconnect with APR/native on Windows Vista/2k8 or later. Patch provided
+       by Douglas Beachy. (markt)
+      </fix>
+      <fix>
+        <bug>54067</bug>: Ensure responses with 1xx response codes are correctly
+        marked as not containing an entity body. This caused an issue for some
+        WebSocket clients when an Transfer-Encoding header was sent with the
+        101 (HTTP upgrade) response. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <scode>
+        <bug>53867</bug>: Optimise the XML escaping provided by the PageContext
+        implementation. Based on a patch by Sheldon Shao. (markt)
+      </scode>
+      <scode>
+        <bug>53896</bug>: Use an optimised CompositeELResolver for Jasper that
+        skips resolvers that are known to be unable to resolve the value. Patch
+        by Jarek Gawor. (markt)
+      </scode>
+      <fix>
+        <bug>53986</bug>: Correct a regression introduced by the fix for
+        <bug>53713</bug>. JSP comments that ended with the sequence ---%> (or
+        any similar sequence with a odd number of - characters) was not
+        correctly parsed. (markt)
+      </fix>
+      <fix>
+        <bug>54011</bug>: Fix a bug in the tag plug-in for
+        <code><c:out></code> that triggered a JSP compilation error if the
+        <code>escapeXml</code> attribute was used. Patch provided by Sheldon
+        Shao. (markt)
+      </fix>
+      <scode>
+        Follow up to <bug>54011</bug>. Simplify generated code for
+        <code><c:out></code>. Based on a patch by Sheldon Shao. (markt)
+      </scode>
+      <fix>
+        <bug>54012</bug>: Fix a bug in the tag plug-in infrastructure that meant
+        the <code><c:set></code> triggered a JSP compilation error when
+        used in a tag file. Based on a patch provided by Sheldon Shao. (markt)
+      </fix>
+      <scode>
+        <bug>54017</bug>: Simplify coercion of <code>String</code> instances to
+        <code>Object</code>. (markt)
+      </scode>
+      <fix>
+        <bug>54144</bug>: Fix a bug in the tag plug-in for
+        <code><c:out></code> that meant that if the value of the tag
+        evaluated to a <code>java.io.Reader</code> object then it was not
+        correctly handled. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        Add getSessionIdsFull operation to mbeans-descriptor. listSessionIdsFull
+        no longer exist. (kfujino)
+      </fix>
+      <fix>
+        <bug>54086</bug>: Fix threading issue when stopping an 
+        <code>NioReceiver</code>. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <add>
+        <bug>54143</bug>: Add display of the memory pools usage (including
+        PermGen) to the Status page of the Manager web application. (kkolinko)
+      </add>
+    </changelog>
+  </subsection>
+  <subsection name="Tribes">
+    <changelog>
+      <fix>
+        <bug>54045</bug>: Make sure getMembers() returns available member when
+        TcpFailureDetector works in static cluster. (kfujino)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.32 (markt)" rtext="2012-10-09">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Revert multiple operation support for the <code>JMXProxyServlet</code>
+        pending further discussion. (schultz)
+      </fix>
+      <fix>
+        Improve session management in <code>CsrfPreventionFilter</code>.
+        (kkolinko)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <fix>
+        Correct the couple of broken links in the Tomcat Javadoc. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <update>
+        Update optional Checkstyle library to 5.6. (kkolinko)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.31 (markt)" rtext="not released">
+  <subsection name="Catalina">
+    <changelog>
+      <update>
+        Add one library from JDK 7 to the value of <code>jarsToSkip</code>
+        property in the <code>catalina.properties</code> file. (kkolinko)
+      </update>
+      <add>
+        <bug>52777</bug>: Add an option to automatically remove old, unused
+        versions (ones where there are no longer any active sessions) of
+        applications deployed using parallel deployment. (markt)
+      </add>
+      <fix>
+        <bug>53828</bug>: Use correct status code when closing a WebSocket
+        connection normally in response to a close frame from a client. (markt)
+      </fix>
+      <update>
+        <code>JMXProxyServlet</code> now allows multiple operation commands like
+        <code>invokeAndSet</code>, <code>invokeAndGet</code>,
+        etc. (schultz) <em>Note</em>: reverted in 7.0.32.
+      </update>
+      <fix>
+        <bug>53843</bug>: <code>request.isAsyncStarted()</code> must continue to
+        return true until the dispatch actually happens (which at the earliest
+        isn't until the thread where <code>startAsync()</code> was called
+        returns to the container). (markt)
+      </fix>
+      <fix>
+        <bug>53863</bug>: Ensure the the implicit servlets (JSP and default) are
+        marked as override-able when using embedded mode. (markt)
+      </fix>
+      <fix>
+        When the <code>DefaultServlet</code> is under heavy load, the HTTP
+        header parser added to address <bug>52811</bug> generates large amounts
+        of garbage and uses significant CPU time. A cache has been added that
+        significantly reduces the overhead of this parser. (markt) 
+      </fix>
+      <fix>
+        <bug>53854</bug>: Make directory listings work correctly when aliases
+        are used. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <scode>
+        <bug>53713</bug>: Performance improvement of up to four times faster
+        parsing of JSP pages. Patch provided by Sheldon Shao. (markt)
+      </scode>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <add>
+        Make the cluster members and the cluster deployer associated with the
+        cluster accessible via JMX. (markt)
+      </add>
+      <fix>
+        Fix a behavior of TcpPingInterceptor#useThread. If set to false, ping
+        thread is never started. (kfujino)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <add>
+        Improve the documentation web application to clarify the difference
+        between the tag and version parameters when using text interface of the
+        Manager web application. (markt)
+      </add>
+      <add>
+        Make sessions saved in the <code>Store</code> associated with a
+        <code>Manager</code> that extends <code>PersistentManager</code>
+        optionally visible (via the showProxySessions Servlet initialisation
+        parameter in web.xml) to the Manager web application. (markt) 
+      </add>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.30 (markt)" rtext="released 2012-09-06">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Automatically delete temporary files used by Servlet 3.0 file
+        upload (for parts which size is greater than
+        <code>file-size-threshold</code> option in web.xml)
+        when request processing completes. (kkolinko)
+      </fix>
+      <fix>
+        <bug>53071</bug>: This additional fix for this issue improves the
+        formatting of Jasper errors (or any exceptions that use a multi-line
+        message) with the <code>ErrorReportValve</code>. (markt)
+      </fix>
+      <fix>
+        <bug>53469</bug>: If a URL passed to
+        <code>javax.servlet.http.HttpServletResponse.encodeURL()</code> cannot
+        be made absolute, never encode it and return it unchanged. Previously,
+        the fix for <bug>53062</bug> meant than an
+        <code>IllegalArgumentException</code> was thrown. (markt)
+      </fix>
+      <fix>
+        <bug>53481</bug>: Added support for SSLHonorCipherOrder to allow
+        the server to impose its cipher order on the client. Based on a patch
+        provided by Marcel &#x160;ebek. This feature requires
+        Tomcat Native 1.1.25 or later. (schultz)
+      </fix>
+      <fix>
+        <bug>53498</bug>: Fix atomicity bugs in use of concurrent collections.
+        Based on a patch by Yu Lin. (markt)
+      </fix>
+      <fix>
+        Correct a regression in the previous fix for <bug>53062</bug> that did
+        not always correctly normalize redirect URLs when the redirect URL
+        included a query string or fragment component. (markt)
+      </fix>
+      <fix>
+        Add missing getter and setter for <code>roleSearchAsUser</code> option
+        on JNDI Realm. (markt)
+      </fix>
+      <update>
+        Add some HTTP status codes registered at IANA. (rjung)
+      </update>
+      <fix>
+        <bug>53531</bug>: Fix ExpandWar.expand to check the return value of
+        File.mkdir and File.mkdirs. (schultz)
+      </fix>
+      <fix>
+        <bug>53535</bug>: Reduce memory footprint when performing class scanning
+        on Context start. Patch provided by Cedomir Igaly. (markt)
+      </fix>
+      <fix>
+        <bug>53541</bug>: Fix JAR scanning when WEB-INF/lib is provided via
+        VirtualDirContext. Patch provided by Philip Zuev. (markt)
+      </fix>
+      <fix>
+        <bug>53574</bug>: Ensure Servlets defined using jsp-file are available
+        when metadata-complete is true. (markt)
+      </fix>
+      <fix>
+        <bug>53584</bug>: Ignore path parameters when comparing URIs for FORM
+        authentication. This prevents users being prompted twice for passwords
+        when logging in when session IDs are being encoded as path parameters.
+        (markt)
+      </fix>
+      <fix>
+        <bug>53623</bug>: When performing a asynchronous dispatch after series
+        of forwards, ensure that the request properties are correct for the
+        request at each stage. (markt) 
+      </fix>
+      <fix>
+        <bug>53624</bug>: Ensure that
+        <code>HttpServletResponse.sendRedirect()</code> works when called after
+        a dispatch from an <code>AsyncContext</code>. (markt)
+      </fix>
+      <fix>
+        <bug>53641</bug>: Correct name of HTTP header used in WebSocket
+        handshake for listing the preferred protocols. (markt)
+      </fix>
+      <scode>
+        Document the constants that were added to the
+        <code>RequestDispatcher</code> interface in Servlet 3.0. (kkolinko)
+      </scode>
+      <fix>
+        Ensure custom error pages are not truncated if the page that triggered
+        the error set a content length header. (markt)
+      </fix>
+      <fix>
+        <bug>53677</bug>: Ensure that a 500 response rather than no response is
+        returned if the HTTP headers exceed the size limit. (markt)
+      </fix>
+      <fix>
+        <bug>53702</bug>: When merging web.xml fragments, allow for
+        <code><jsp-property-group></code> elements having multiple
+        <code><url-pattern></code> elements. (markt)
+      </fix>
+      <add>
+        Always make the resulting web.xml available even if metadata-complete is
+        true. (markt)
+      </add>
+      <fix>
+        <bug>53714</bug>: Provide separate system properties to control which
+        JARs are excluded from which scans when using the JarScanner. This
+        allows JARs to be excluded from all scans or only from TLD scanning
+        and/or Servlet 3.0 pluggability scanning. (markt)
+      </fix>
+      <update>
+        Add several JDK libraries to the value of <code>jarsToSkip</code>
+        property in the <code>catalina.properties</code> file. (markt, kkolinko)
+      </update>
+      <fix>
+        Fix typos etc. in the code that logs merged web.xml (as enabled by
+        <code>logEffectiveWebXml</code> option on Context). (kkolinko)
+      </fix>
+      <fix>
+        <bug>53758</bug>: When adding filters via
+        <code>FilterRegistration.Dynamic</code> the filters were added at the
+        wrong point because the <code>isMatchAfter </code> logic was inverted.
+        (markt)
+      </fix>
+      <fix>
+        <bug>53783</bug>: Correctly handle JARs generated by tools that do not
+        create specific entries for directories. Patch provided by Violeta
+        Georgieva. (markt)
+      </fix>
+      <fix>
+        Improvements to DIGEST authenticator including the disabling caching of
+        authenticated user in session by default, tracking server rather than
+        client nonces and better handling of stale nonce values. (markt)
+      </fix>
+      <fix>
+        Improve performance of DIGEST authenticator for concurrent requests.
+        (markt)
+      </fix>
+      <fix>
+        Remove unneeded handling of FORM authentication in RealmBase. (kkolinko)
+      </fix>
+      <fix>
+        <bug>53800</bug>: <code>FileDirContext.list()</code> did not provide
+        correct paths for subdirectories. Patch provided by Kevin Wooten.
+        (kkolinko)
+      </fix>
+      <fix>
+        <bug>53801</bug>: Overlapping URL patterns were sometimes merged
+        incorrectly in security constraints leading to incorrect 401 responses.
+        Note: it was possible for access to be denied when it should have been
+        granted but it was not possible for access to be granted when it should
+        have been denied. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Remove the <code>socket.soTrafficClass</code> from the BIO and NIO
+        HTTP and AJP connectors because any use of the option is either ignored
+        or in some cases (Java 7 with NIO) throws an Exception. (mark)
+      </fix>
+      <fix>
+        Prevent possible NPE when processing Comet requests during Connector
+        shutdown. (markt)
+      </fix>
+      <fix>
+        <bug>42181</bug>: Better handling of edge conditions in chunk header
+        processing. (kkolinko)
+      </fix>
+      <fix>
+        <bug>53697</bug>: Correct a regression in the fix for <bug>51881</bug>
+        that mean that in some circumstances the <code>comet</code> flag was not
+        reset on <code>HttpAprProcessor</code> instances. This caused problems
+        when the Processor was re-used for a new connection that would trigger a
+        <code>NullPointerException</code> and could result in a JVM crash.
+        (markt)
+      </fix>
+      <fix>
+        <bug>53725</bug>: Fix possible corruption of GZIP'd output.
+        (markt/kkolinko)
+      </fix>
+      <fix>
+        Better parsing of line-terminators for requests using chunked encoding.
+        (markt)
+      </fix>
+      <fix>
+        Further improvements to handling of Comet END events when the connector
+        is stopped. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>53545</bug>: Ensure buffered data is cleared when using a
+        jsp:forward action inside a classic custom tag. (markt)
+      </fix>
+      <fix>
+        <bug>53654</bug>: Support <code>file://</code> URLs for JSP
+        dependencies. Patch provided by Viola Lu. (markt)
+      </fix>
+      <fix>
+        <bug>53792</bug>: Support <code>MethodExpression</code>s that include a
+        method invocation that is not at the end of the expression. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        Fix an issue when running under Java 7 which throws exceptions when
+        trying to set an invalid option whereas Java 6 silently swallowed them.
+        The option using the problem was <code>soTrafficClass</code>.
+        Investigations showed that this option had no effect for Cluster Channel
+        Receivers so it was removed. (markt)
+      </fix>
+      <fix>
+        <bug>53513</bug>: Fix race condition between the processing of session
+        sync message and transfer complete message. (kfujino)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <fix>
+        Update JSTL version information in the JNDI section of the documentation
+        web application. (markt)
+      </fix>
+      <fix>
+        <bug>53524</bug>: Correct a typo in the cluster how-to section of the
+        documentation web application. Also fix a handful of spelling errors.
+        (markt)
+      </fix>
+      <fix>
+        <bug>53601</bug>: Clarify in documentation that building Apache Tomcat 7
+        from sources requires a Java 6 JDK. (kkolinko)
+      </fix>
+      <fix>
+        <bug>53653</bug>: Allow for wrapped source code example in
+        config/context.html. Patch provided by Terence Bandoian. (schultz)
+      </fix>
+      <update>
+        <bug>53793</bug>: Change links on the list of applications in the
+        Manager to point to '/appname/' instead of '/appname'. (kkolinko)
+      </update>
+    </changelog>
+  </subsection>
+  <subsection name="Tribes">
+    <changelog>
+      <fix>
+        Avoid potential NPE identified by Find Bugs in
+        <code>org.apache.catalina.tribes.io.ReplicationStream</code>. (markt)
+      </fix>
+      <fix>
+        <bug>53606</bug>: Fix potential NPE in <code>TcpPingInterceptor</code>.
+        Based on a patch by F. Arnoud. (markt)
+      </fix>
+      <fix>
+        <bug>53607</bug>: To avoid NPE, set TCP PING data to ChannelMessage.
+        Patch provided by F.Arnoud (kfujino)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <fix>
+        <bug>53701</bug>: Javadoc fixes. Patch provided by sebb. (markt)
+      </fix>
+      <scode>
+        Remove some unused code from Tomcat's package renamed, cut-down
+        copy of Commons BCEL used for annotation scanning. (markt)
+      </scode>
+      <add>
+        <bug>53735</bug>: Add support for Java 7 byte code to Tomcat's
+        package renamed, cut-down copy of Commons BCEL used for annotation
+        scanning. (markt)
+      </add>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.29 (markt)" rtext="released 2012-07-08">
+  <subsection name="Catalina">
+    <changelog>
+      <add>
+        Add support for searching for roles in JNDI/LDAP
+        using another value than the actual DN or username specified.
+        Rather it will use a value from the users directory entry.
+        The new attribute introduced to the JNDIRealm is userRoleAttribute
+        (fhanik)
+      </add>
+      <fix>
+        Fix checking of recommended tcnative library version when using the APR
+        connector. (rjung)
+      </fix>
+      <update>
+        <bug>50306</bug>: Improve StuckThreadDetectionValve: add
+        stuckThreadNames property as a pair for the stuckThreadIds one,
+        add thread ids to the log messages. (kkolinko)
+      </update>
+      <add>
+        <bug>52135</bug>: Add support for a default error page to be defined in
+        web.xml by defining an error page with just a nested location element.
+        It appears this feature was intended to be included in the Servlet 3.0
+        specification but was accidently left out. (markt)
+      </add>
+      <fix>
+        <bug>53450</bug>: Correct regression in fix for <bug>52999</bug> that
+        could easily trigger a deadlock when deploying a ROOT web application.
+        (markt)
+      </fix>
+      <fix>
+        As per section 1.6.2 of the Servlet 3.0 specification and clarification
+        from the Servlet Expert Group, the servlet specification version
+        declared in web.xml no longer controls if Tomcat scans for annotations.
+        Annotation scanning is now always performed - regardless of the version
+        declared in web.xml - unless metadata complete is set to true. (markt)
+      </fix>
+      <fix>
+        <bug>53619</bug>: As per clarification from the Servlet Expert Group,
+        JARs will always be scanned for ServletContainerInitializers regardless
+        of the setting of metadata complete. However, if an absolute ordering is
+        specified and a JAR is excluded from that ordering it will not be
+        scanned for ServletContainerInitializers nor will it be scanned for
+        matches to any HandleTypes annotations. (markt) 
+      </fix>
+      <add>
+        <bug>53465</bug>: Populate mapped-name property for resources defined in
+        web.xml. Based on a patch by Violeta Georgieva. (markt) 
+      </add>
+      <add>
+        Make the request available when establishing a WebSocket connection.
+        (markt)
+      </add>
+      <fix>
+        <bug>53467</bug>: Correct a regression in the fix for <bug>53257</bug>
+        that introduced problems for JSPs that used characters that must be
+        encoded if used in a URI. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>53430</bug>: Avoid a JVM crash when a connector that requires the
+        APR/native library is explicitly specified and the library, or a recent 
+        enough  version of it, is not available. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>53421</bug>: Provide a more helpful error message if a getter or
+        setter cannot be found for a bean property when using expression
+        language. (markt)
+      </fix>
+      <fix>
+       <bug>53460</bug>: Allow container to handle errors if the creation of the
+       PageContext fails rather than swallowing the error. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <fix>
+        Update the WebSocket examples in the examples web application so that
+        they work with secure connections (wss) as well as non-secure (ws)
+        connections. (markt)  
+      </fix>
+      <fix>
+        <bug>53456</bug>: Minor corrections and improvements to the HTTP
+        connector configuration reference. Patch provided by sebb. (markt)
+      </fix>
+      <fix>
+        <bug>53459</bug>: Correction and clarifications to the SSL Connector
+        configuration examples in the SSL how-to. (markt)
+      </fix>
+      <fix>
+        <bug>53464</bug>: Correct reference to sample init.d script for use with
+        jsvc in the documentation web application. (markt)
+      </fix>
+      <fix>
+        <bug>53473</bug>: Correct the allowed values for the SSI option
+        <code>isVirtualWebappRelative</code> which are <code>true</code> or
+        <code>false</code>. (markt)
+      </fix>
+      <fix>
+        Document <code>roleNested</code> property of <code>JNDIRealm</code>
+        in Configuration Reference. (kkolinko)
+      </fix>
+    </changelog>
+  </subsection>
+    <subsection name="jdbc-pool">
+    <changelog>
+      <fix>
+        <bug>53445</bug> (<rev>1354173</rev>):
+        Allow configurable name for SlowQueryReportJmx (fhanik)
+      </fix>
+      <fix>
+        <bug>53416</bug> (<rev>1354641</rev>):
+        Multiple pools with the same name should register under JMX (fhanik)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <fix>
+        Fix cleanup of temporary files in <code>TestNamingContext</code> test.
+        (kkolinko)
+      </fix>
+      <fix>
+        Remove a few files from the source distribution that are not required
+        since they are copied / generated during the build. (markt)
+      </fix>
+      <fix>
+        Add manifest files to the set of files for which the line-ending is
+        changed to match the OS defaults in the source distributions. (markt)
+      </fix>
+      <scode>
+        Align Jk Ant tasks definitions between antlib.xml and catalina.tasks
+        files, introducing <code>jkupdate</code> as synonym for
+        <code>jkstatus</code>. The latter one is deprecated.
+        Simplify <code>bin/catalina-tasks.xml</code>, replacing
+        <code>taskdef</code> with <code>typedef</code> and adding Ant condition
+        implementations used with JMX to <code>jmxaccessor.tasks</code> file.
+        (kkolinko)
+      </scode>
+      <fix>
+        <bug>53454</bug>: Return correct content-length header for HEAD requests
+        when content length is greater than 2GB. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.28 (markt)" rtext="released 2012-06-19">
   <subsection name="Catalina">
     <changelog>
       <fix>
@@ -101,6 +842,12 @@
         (markt)
       </fix>
       <fix>
+        <bug>53047</bug>: If a JDBC Realm or DataSource Realm is configured for
+        an all roles mode that only requires authorization (and no roles) and no
+        role table or column is defined, don't populate the Principal's roles.
+        (markt)
+      </fix>
+      <fix>
         <bug>53056</bug>: Add APR version number to tcnative version INFO log
         message. (schultz)
       </fix>
@@ -235,7 +982,7 @@
       <fix>
         <bug>53353</bug>: Make the internal HTTP header parser more tolerant of
         Content-Type values that contain invalid parameters by ignoring the
-        invalid parameters. (markt)
+        invalid parameters. It is a followup to bug <bug>52811</bug>. (markt)
       </fix>
       <fix>
         <bug>53354</bug>: Correctly handle <code>@WebFilter</code> annotations
@@ -501,6 +1248,11 @@
         found. (markt)
       </fix>
       <fix>
+        <bug>52811</bug>: Fix parsing of Content-Type header in
+        <code>HttpServletResponse.setContentType()</code>. Introduces
+        a new HTTP header parser that follows RFC2616. (markt/kkolinko)
+      </fix>
+      <fix>
         <bug>52830</bug>: Correct JNDI lookups when using
         <code>javax.naming.Name</code> to identify the resource rather than a
         <code>java.lang.String</code>. (markt)
diff --git a/webapps/docs/cluster-howto.xml b/webapps/docs/cluster-howto.xml
index 18d4f0a..23c0b7a 100644
--- a/webapps/docs/cluster-howto.xml
+++ b/webapps/docs/cluster-howto.xml
@@ -47,7 +47,7 @@
   <p>
     Using the above configuration will enable all-to-all session replication
     using the <code>DeltaManager</code> to replicate session deltas. By all-to-all we mean that the session gets replicated to all the other
-    nodes in the cluster. This works great for smaller cluster but we don't recommend it for larger clusters(a lot of tomcat nodes).
+    nodes in the cluster. This works great for smaller cluster but we don't recommend it for larger clusters(a lot of Tomcat nodes).
     Also when using the delta manager it will replicate to all nodes, even nodes that don't have the application deployed.<br/>
     To get around this problem, you'll want to use the BackupManager. This manager only replicates the session data to one backup
     node, and only to nodes that have the application deployed. Downside of the BackupManager: not quite as battle tested as the delta manager.
@@ -147,7 +147,7 @@ should be completed:</p>
    The all-to-all replication is an algorithm that is only efficient when the clusters are small. For larger clusters,  to use
    a primary-secondary session replication where the session will only be stored at one backup server simply setup the BackupManager. <br/>
    Currently you can use the domain worker attribute (mod_jk > 1.2.8) to build cluster partitions
-   with the potential of having a more scaleable cluster solution with the DeltaManager(you'll need to configure the domain interceptor for this).
+   with the potential of having a more scalable cluster solution with the DeltaManager(you'll need to configure the domain interceptor for this).
    In order to keep the network traffic down in an all-to-all environment, you can split your cluster
    into smaller groups. This can be easily achieved by using different multicast addresses for the different groups.
    A very simple setup would look like this:
@@ -209,7 +209,7 @@ should be completed:</p>
     The JvmRouteBinderValve rewrites the session id to ensure that the next request will remain sticky
     (and not fall back to go to random nodes since the worker is no longer available) after a fail over.
     The valve rewrites the JSESSIONID value in the cookie with the same name.
-    Not having this valve in place, will make it harder to ensure stickyness in case of a failure for the mod_jk module.
+    Not having this valve in place, will make it harder to ensure stickiness in case of a failure for the mod_jk module.
 </p>
 <p>
     By default, if no valves are configured, the JvmRouteBinderValve is added on.
@@ -337,8 +337,8 @@ should be completed:</p>
         <code>StaticMembershipInterceptor</code> if you want to extend your membership to points beyond multicasting.
         The address attribute is the multicast address used and the port is the multicast port. These two together
         create the cluster separation. If you want a QA cluster and a production cluster, the easiest config is to
-        have the QA cluster be on a separate multicast address/port combination the the production cluster.<br/>
-        The membership component broadcasts TCP adress/port of itselt to the other nodes so that communication between
+        have the QA cluster be on a separate multicast address/port combination than the production cluster.<br/>
+        The membership component broadcasts TCP address/port of itself to the other nodes so that communication between
         nodes can be done over TCP. Please note that the address being broadcasted is the one of the
         <code>Receiver.address</code> attribute.
         <br/>For more info, Please visit the <a href="config/cluster-membership.html">reference documentation</a>
@@ -382,7 +382,7 @@ should be completed:</p>
     <p>
         Tribes uses a stack to send messages through. Each element in the stack is called an interceptor, and works much like the valves do
         in the Tomcat servlet container.
-        Using interceptors, logic can be broken into more managable pieces of code. The interceptors configured above are:<br/>
+        Using interceptors, logic can be broken into more manageable pieces of code. The interceptors configured above are:<br/>
         TcpFailureDetector - verifies crashed members through TCP, if multicast packets get dropped, this interceptor protects against false positives,
         ie the node marked as crashed even though it still is alive and running.<br/>
         MessageDispatch15Interceptor - dispatches messages to a thread (thread pool) to send message asynchrously.<br/>
@@ -627,24 +627,6 @@ set CATALINA_OPTS=\
 -Dcom.sun.management.jmxremote.authenticate=false
 </source>
 </p>
-<p>Activate JMX with JDK 1.4:
-<ol>
-<li>Install the compat package</li>
-<li>Install the mx4j-tools.jar at common/lib (use the same mx4j version as your tomcat release)</li>
-<li>Configure a MX4J JMX HTTP Adaptor at your AJP Connector<p></p>
-<source>
-<Connector port="${AJP.PORT}"
-   handler.list="mx"
-   mx.enabled="true"
-   mx.httpHost="${JMX.HOST}"
-   mx.httpPort="${JMX.PORT}"
-   protocol="AJP/1.3" />
-</source>
-</li>
-<li>Start your tomcat and look with your browser to http://${JMX.HOST}:${JMX.PORT}</li>
-<li>With the connector parameter <code>mx.authMode="basic" mx.authUser="tomcat" mx.authPassword="strange"</code> you can control the access!</li>
-</ol>
-</p>
 <p>
 List of Cluster Mbeans<br/>
 <table border="1" cellpadding="5">
@@ -671,6 +653,20 @@ List of Cluster Mbeans<br/>
   </tr>
 
   <tr>
+    <td>FarmWarDeployer</td>
+    <td>Manages the process of deploying an application to all nodes in the cluster</td>
+    <td>Not supported</td>
+    <td><code>type=Cluster, host=${HOST}, component=deployer</code></td>
+  </tr>
+
+  <tr>
+    <td>Member</td>
+    <td>Represents a node in the cluster</td>
+    <td>type=Cluster, component=member, name=${NODE_NAME}</td>
+    <td><code>type=Cluster, host=${HOST}, component=member, name=${NODE_NAME}</code></td>
+  </tr>
+
+  <tr>
     <td>ReplicationValve</td>
     <td>This valve control the replication to the backup nodes</td>
     <td><code>type=Valve,name=ReplicationValve</code></td>
diff --git a/webapps/docs/config/ajp.xml b/webapps/docs/config/ajp.xml
index b2497c7..6a0196a 100644
--- a/webapps/docs/config/ajp.xml
+++ b/webapps/docs/config/ajp.xml
@@ -479,14 +479,6 @@
         <p>This is equivalent to standard attribute
         <strong>connectionTimeout</strong>.</p>
       </attribute>
-      <attribute name="socket.soTrafficClass" required="false">
-        <p>(byte)Value between <code>0</code> and <code>255</code> for the
-        traffic class on the socket. JVM default used if not set.</p>
-        <p><strong>Note:</strong> On some JDK versions, setting
-        <strong>soTrafficClass</strong> causes a problem. A work around for this
-        is to add the <code>-Djava.net.preferIPv4Stack=true</code> value to your
-        JVM options.</p>
-      </attribute>
       <attribute name="socket.performanceConnectionTime" required="false">
         <p>(int)The first value for the performance settings. See
         <a href="http://docs.oracle.com/javase/6/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)">Socket Performance Options</a>
diff --git a/webapps/docs/config/cluster-interceptor.xml b/webapps/docs/config/cluster-interceptor.xml
index 7b833e8..e23e46f 100644
--- a/webapps/docs/config/cluster-interceptor.xml
+++ b/webapps/docs/config/cluster-interceptor.xml
@@ -55,6 +55,7 @@
     <li><code>org.apache.catalina.tribes.group.interceptors.DomainFilterInterceptor</code></li>
     <li><code>org.apache.catalina.tribes.group.interceptors.FragmentationInterceptor</code></li>
     <li><code>org.apache.catalina.tribes.group.interceptors.GzipInterceptor</code></li>
+    <li><code>org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor</code></li>
    </ul>
  </p>
 </section>
@@ -143,6 +144,20 @@
    <attributes>
    </attributes>
   </subsection>
+  <subsection name="org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor Attributes">
+   <attributes>
+     <attribute name="interval" required="false">
+       If useThread == true, defines the interval of sending a ping message.
+       default is 1000 ms.
+     </attribute>
+     <attribute name="useThread" required="false">
+       Flag of whether to start a thread for sending a ping message.
+       If set to true, this interceptor will start a local thread for sending a ping message.
+       if set to false, channel heartbeat will send a ping message.
+       default is false.
+     </attribute>
+   </attributes>
+  </subsection>
   <subsection name="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor Attributes">
    <attributes>
      <attribute name="interval" required="false">
diff --git a/webapps/docs/config/cluster-receiver.xml b/webapps/docs/config/cluster-receiver.xml
index e54600e..def130a 100644
--- a/webapps/docs/config/cluster-receiver.xml
+++ b/webapps/docs/config/cluster-receiver.xml
@@ -142,11 +142,6 @@
     <attribute name="soReuseAddress" required="false">
      Boolean value for the socket SO_REUSEADDR option. Possible values are <code>true</code> or <code>false</code>.
     </attribute>
-    <attribute name="soTrafficClass" required="false">
-     Sets the traffic class level for the socket, the value is between 0 and 255.
-     Different values are defined in <a href="http://docs.oracle.com/javase/6/docs/api/java/net/Socket.html#setTrafficClass(int)">
-     java.net.Socket#setTrafficClass(int)</a>.
-    </attribute>
     <attribute name="tcpNoDelay" required="false">
      Boolean value for the socket TCP_NODELAY option. Possible values are <code>true</code> or <code>false</code>.
      The default value is <code>true</code>
diff --git a/webapps/docs/config/context.xml b/webapps/docs/config/context.xml
index 6a16709..5a7d532 100644
--- a/webapps/docs/config/context.xml
+++ b/webapps/docs/config/context.xml
@@ -82,6 +82,9 @@
   <li>If session information is present in the request but no matching session
   can be found, use the latest version.</li>
   </ul>
+  <p>The <a href="host.html">Host</a> may be configured (via the
+  <code>undeployOldVersions</code>) to remove old versions deployed in this way
+  once they are no longer in use.</p>
   </subsection>
 
   <subsection name="Naming">
@@ -955,13 +958,9 @@
 
       <attribute name="type" required="true">
         <p>The fully qualified Java class name expected by the web application
-        for this environment entry.  Must be one of the legal values for
+        for this environment entry.  Must be a legal value for
         <code><env-entry-type></code> in the web application deployment
-        descriptor:  <code>java.lang.Boolean</code>,
-        <code>java.lang.Byte</code>, <code>java.lang.Character</code>,
-        <code>java.lang.Double</code>, <code>java.lang.Float</code>,
-        <code>java.lang.Integer</code>, <code>java.lang.Long</code>,
-        <code>java.lang.Short</code>, or <code>java.lang.String</code>.</p>
+        descriptor.</p>
       </attribute>
 
       <attribute name="value" required="true">
@@ -1339,18 +1338,25 @@ mywebapp/
                 classes/
 </source>
     <p>The configuration is:</p>
-<source>
+
+<source wrapped="true">
 <Context path="/mywebapp" docBase="/Users/theuser/mywebapp/src/main/webapp" >
+<indent>
   <Resources className="org.apache.naming.resources.VirtualDirContext"
-    extraResourcePaths=
-    "/WEB-INF/classes=/Users/theuser/mywebapp/target/classes,/pictures=/Users/theuser/mypictures,/movies=/Users/theuser/mymovies" />
+    <indent><outdent>extraResourcePaths="/WEB-INF/classes=/Users/theuser/mywebapp/target/classes,/pictures=/Users/theuser/mypictures,/movies=/Users/theuser/mymovies"</outdent></indent>
+    <indent>/></indent>
+</indent>
+<indent>
   <Loader className="org.apache.catalina.loader.VirtualWebappLoader"
-    virtualClasspath="/Users/theuser/mywebapp/target/classes;
-      /Users/theuser/mylib/target/classes;
-      /Users/theuser/.m2/repository/log4j/log4j/1.2.15/log4j-1.2.15.jar" />
+    <indent><outdent>virtualClasspath="/Users/theuser/mywebapp/target/classes;/Users/theuser/mylib/target/classes;/Users/theuser/.m2/repository/log4j/log4j/1.2.15/log4j-1.2.15.jar"</outdent></indent>
+    <indent>/></indent>
+</indent>
+<indent>
   <JarScanner scanAllDirectories="true" />
+</indent>
 </Context>
 </source>
+
     <p>Note that resources in mylib/target/classes/META-INF/resources/ are mapped to / as
     required by servlet 3 specification.</p>
   </subsection>
diff --git a/webapps/docs/config/filter.xml b/webapps/docs/config/filter.xml
index b937abd..3120ee7 100644
--- a/webapps/docs/config/filter.xml
+++ b/webapps/docs/config/filter.xml
@@ -131,6 +131,11 @@
 
     <attributes>
 
+      <attribute name="denyStatus" required="false">
+        <p>HTTP response status code that is used when rejecting denied
+        request. The default value is <code>403</code>.</p>
+      </attribute>
+
       <attribute name="entryPoints" required="false">
         <p>A comma separated list of URLs that will not be tested for the
         presence of a valid nonce. They are used to provide a way to navigate
diff --git a/webapps/docs/config/globalresources.xml b/webapps/docs/config/globalresources.xml
index 629f0d2..382e45f 100644
--- a/webapps/docs/config/globalresources.xml
+++ b/webapps/docs/config/globalresources.xml
@@ -115,13 +115,9 @@
 
       <attribute name="type" required="true">
         <p>The fully qualified Java class name expected by the web application
-        for this environment entry.  Must be one of the legal values for
+        for this environment entry.  Must be a legal value for
         <code><env-entry-type></code> in the web application deployment
-        descriptor:  <code>java.lang.Boolean</code>,
-        <code>java.lang.Byte</code>, <code>java.lang.Character</code>,
-        <code>java.lang.Double</code>, <code>java.lang.Float</code>,
-        <code>java.lang.Integer</code>, <code>java.lang.Long</code>,
-        <code>java.lang.Short</code>, or <code>java.lang.String</code>.</p>
+        descriptor.</p>
       </attribute>
 
       <attribute name="value" required="true">
@@ -192,6 +188,15 @@
         application uses a <code><resource-env-ref></code> instead.</p>
       </attribute>
 
+      <attribute name="closeMethod" required="false">
+        <p>Name of the zero-argument method to call on a singleton resource when
+        it is no longer required. This is intended to speed up clean-up of
+        resources that would otherwise happen as part of garbage collection.
+        This attribute is ignored if the <code>singleton</code> attribute is
+        false. If not specificed, no default is defined and no close method will
+        be called.</p>
+      </attribute>
+
       <attribute name="description" required="false">
         <p>Optional, human-readable description of this resource.</p>
       </attribute>
@@ -208,6 +213,19 @@
         connections are assumed to be shareable.</p>
       </attribute>
 
+      <attribute name="singleton" required="false">
+        <p>Specify whether this resource definition is for a singleton resource,
+        i.e. one where there is only a single instance of the resource. If this
+        attribute is <code>true</code>, multiple JNDI lookups for this resource
+        will return the same object. If this attribute is <code>false</code>,
+        multiple JNDI lookups for this resource will return different objects.
+        This attribute must be <code>true</code> for
+        <code>javax.sql.DataSource</code> resources to enable JMX registration
+        of the DataSource. The value of this attribute must be <code>true</code>
+        or <code>false</code>. By default, this attribute is <code>true</code>.
+        </p>
+      </attribute>
+
       <attribute name="type" required="true">
         <p>The fully qualified Java class name expected by the web
         application when it performs a lookup for this resource.</p>
diff --git a/webapps/docs/config/host.xml b/webapps/docs/config/host.xml
index a65b038..8c80000 100644
--- a/webapps/docs/config/host.xml
+++ b/webapps/docs/config/host.xml
@@ -201,6 +201,14 @@
         not specified, the default value of 1 will be used.</p>
       </attribute>
 
+      <attribute name="undeployOldVersions" required="false">
+        <p>This flag determines if Tomcat, as part of the auto deployment
+        process, will check for old, unused versions of web applications
+        deployed using parallel deployment and, if any are found, remove them.
+        This flag only applies if <code>autoDeploy</code> is true. If not
+        specified the default value of false will be used.</p>
+      </attribute>
+
     </attributes>
 
   </subsection>
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index 905230b..d252b84 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -48,8 +48,8 @@
 
   <p>If you wish to configure the <strong>Connector</strong> that is used
   for connections to web servers using the AJP protocol (such as the
-  <code>mod_jk 1.2.x</code> connector for Apache 1.3), see
-  <a href="ajp.html">here</a> instead.</p>
+  <code>mod_jk 1.2.x</code> connector for Apache 1.3), please refer to the
+  <a href="ajp.html">AJP Connector</a> documentation.</p>
 
   <p>Each incoming request requires
   a thread for the duration of that request.  If more simultaneous requests
@@ -558,14 +558,6 @@
         <p>This is equivalent to standard attribute
         <strong>connectionTimeout</strong>.</p>
       </attribute>
-      <attribute name="socket.soTrafficClass" required="false">
-        <p>(byte)Value between <code>0</code> and <code>255</code> for the
-        traffic class on the socket. JVM default used if not set.</p>
-        <p><strong>Note:</strong> On some JDK versions, setting
-        <strong>soTrafficClass</strong> causes a problem. A work around for this
-        is to add the <code>-Djava.net.preferIPv4Stack=true</code> value to your
-        JVM options.</p>
-      </attribute>
       <attribute name="socket.performanceConnectionTime" required="false">
         <p>(int)The first value for the performance settings. See
         <a href="http://docs.oracle.com/javase/6/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int)">Socket Performance Options</a>
@@ -896,11 +888,16 @@
   attributes to the values <code>https</code> and <code>true</code>
   respectively, to pass correct information to the servlets.</p>
 
-  <p>The BIO and NIO connectors used the JSSE SSL whereas the APR/native
+  <p>The BIO and NIO connectors use the JSSE SSL whereas the APR/native
   connector uses OpenSSL. Therefore, in addition to using different attributes
   to configure SSL, the APR/native connector also requires keys and certificates
   to be provided in a different format.</p>
 
+  <p>For more information, see the
+  <a href="../ssl-howto.html">SSL Configuration HOW-TO</a>.</p>
+
+  <subsection name="SSL Support - BIO and NIO">
+
   <p>The BIO and NIO connectors use the following attributes to configure SSL:
   </p>
 
@@ -1090,6 +1087,10 @@
 
   </attributes>
 
+  </subsection>
+
+  <subsection name="SSL Support - APR/Native">
+
   <p>When APR/native is enabled, the HTTPS connector will use a socket poller
   for keep-alive, increasing scalability of the server. It also uses OpenSSL,
   which may be more optimized than JSSE depending on the processor being used,
@@ -1176,6 +1177,12 @@
       supported).</p>
     </attribute>
 
+    <attribute name="SSLHonorCipherOrder" required="false">
+      <p>Set to <code>true</code> to enforce the server's cipher order
+      (from the <code>SSLCipherSuite</code> setting) instead of allowing
+      the client to choose the cipher (which is the default).</p>
+    </attribute>
+
     <attribute name="SSLPassword" required="false">
       <p>Pass phrase for the encrypted private key. If "SSLPassword" is not
       provided, the callback function should prompt for the pass phrase.</p>
@@ -1203,15 +1210,14 @@
 
   </attributes>
 
-  <p>For more information, see the
-  <a href="../ssl-howto.html">SSL Configuration HOW-TO</a>.</p>
+  </subsection>
 
   </subsection>
   <subsection name="Connector Comparison">
 
     <p>Below is a small chart that shows how the connectors differentiate.</p>
     <source>
-                       Java Blocking Connector   Java Nio Blocking Connector   APR/native Connector
+                       Java Blocking Connector   Java Non Blocking Connector   APR/native Connector
                                  BIO                         NIO                       APR
     Classname              Http11Protocol             Http11NioProtocol         Http11AprProtocol
     Tomcat Version           3.x onwards                 6.x onwards              5.5.x onwards
diff --git a/webapps/docs/config/realm.xml b/webapps/docs/config/realm.xml
index 373730b..cbf0ddf 100644
--- a/webapps/docs/config/realm.xml
+++ b/webapps/docs/config/realm.xml
@@ -82,19 +82,17 @@
 
     </attributes>
 
-  </subsection>
-
-
-  <subsection name="Standard Implementation">
-
     <p>Unlike most Catalina components, there are several standard
     <strong>Realm</strong> implementations available.  As a result,
     the <code>className</code> attribute MUST be used to select the
     implementation you wish to use.</p>
 
-    <h3>JDBC Database Realm (org.apache.catalina.realm.JDBCRealm)</h3>
+  </subsection>
+
 
-    <p>The <strong>JDBC Database Realm</strong> connects Catalina to
+  <subsection name="JDBC Database Realm - org.apache.catalina.realm.JDBCRealm">
+
+    <p>The <strong>JDBC Database Realm</strong> connects Tomcat to
     a relational database, accessed through an appropriate JDBC driver,
     to perform lookups of usernames, passwords, and their associated
     roles.  Because the lookup is done each time that it is required,
@@ -118,6 +116,11 @@
         authenticated and no check will be made for assigned roles unless roles
         are defined in web.xml in which case the user must be assigned at least
         one of those roles.</p>
+        <p>When this attribute has the value of <code>authOnly</code> or
+        <code>strictAuthOnly</code>, the <strong>roleNameCol</strong> and
+        <strong>userRoleTable</strong> attributes become optional. If those two
+        attributes are omitted, the user's roles will not be loaded by this
+        Realm.</p>
       </attribute>
 
       <attribute name="connectionName" required="true">
@@ -151,9 +154,12 @@
         used to connect to the authentication database.</p>
       </attribute>
 
-      <attribute name="roleNameCol" required="true">
+      <attribute name="roleNameCol" required="false">
         <p>Name of the column, in the "user roles" table, which contains
         a role name assigned to the corresponding user.</p>
+        <p>This attribute is <strong>required</strong> in majority of
+        configurations. See <strong>allRolesMode</strong> attribute for
+        a rare case when it can be omitted.</p>
       </attribute>
 
       <attribute name="stripRealmForGss" required="false">
@@ -164,7 +170,7 @@
 
       <attribute name="userCredCol" required="true">
         <p>Name of the column, in the "users" table, which contains
-        the user's credentials (i.e. password(.  If a value for the
+        the user's credentials (i.e. password).  If a value for the
         <code>digest</code> attribute is specified, this component
         will assume that the passwords have been encoded with the
         specified algorithm.  Otherwise, they will be assumed to be
@@ -176,10 +182,13 @@
         that contains the user's username.</p>
       </attribute>
 
-      <attribute name="userRoleTable" required="true">
+      <attribute name="userRoleTable" required="false">
         <p>Name of the "user roles" table, which must contain columns
         named by the <code>userNameCol</code> and <code>roleNameCol</code>
         attributes.</p>
+        <p>This attribute is <strong>required</strong> in majority of
+        configurations. See <strong>allRolesMode</strong> attribute for
+        a rare case when it can be omitted.</p>
       </attribute>
 
       <attribute name="userTable" required="true">
@@ -202,12 +211,12 @@
     information on setting up container managed security using the
     JDBC Database Realm component.</p>
 
+  </subsection>
+
 
-    <h3>
-      DataSource Database Realm (org.apache.catalina.realm.DataSourceRealm)
-    </h3>
+  <subsection name="DataSource Database Realm - org.apache.catalina.realm.DataSourceRealm">
 
-    <p>The <strong>DataSource Database Realm</strong> connects Catalina to
+    <p>The <strong>DataSource Database Realm</strong> connects Tomcat to
     a relational database, accessed through a JNDI named JDBC DataSource
     to perform lookups of usernames, passwords, and their associated
     roles.  Because the lookup is done each time that it is required,
@@ -240,6 +249,11 @@
         authenticated and no check will be made for assigned roles unless roles
         are defined in web.xml in which case the user must be assigned at least
         one of those roles.</p>
+        <p>When this attribute has the value of <code>authOnly</code> or
+        <code>strictAuthOnly</code>, the <strong>roleNameCol</strong> and
+        <strong>userRoleTable</strong> attributes become optional. If those two
+        attributes are omitted, the user's roles will not be loaded by this
+        Realm.</p>
       </attribute>
 
       <attribute name="dataSourceName" required="true">
@@ -259,9 +273,12 @@
         global DataSource.</p>
       </attribute>
 
-      <attribute name="roleNameCol" required="true">
+      <attribute name="roleNameCol" required="false">
         <p>Name of the column, in the "user roles" table, which contains
         a role name assigned to the corresponding user.</p>
+        <p>This attribute is <strong>required</strong> in majority of
+        configurations. See <strong>allRolesMode</strong> attribute for
+        a rare case when it can be omitted.</p>
       </attribute>
 
       <attribute name="stripRealmForGss" required="false">
@@ -272,7 +289,7 @@
 
       <attribute name="userCredCol" required="true">
         <p>Name of the column, in the "users" table, which contains
-        the user's credentials (i.e. password(.  If a value for the
+        the user's credentials (i.e. password).  If a value for the
         <code>digest</code> attribute is specified, this component
         will assume that the passwords have been encoded with the
         specified algorithm.  Otherwise, they will be assumed to be
@@ -284,10 +301,13 @@
         that contains the user's username.</p>
       </attribute>
 
-      <attribute name="userRoleTable" required="true">
+      <attribute name="userRoleTable" required="false">
         <p>Name of the "user roles" table, which must contain columns
         named by the <code>userNameCol</code> and <code>roleNameCol</code>
         attributes.</p>
+        <p>This attribute is <strong>required</strong> in majority of
+        configurations. See <strong>allRolesMode</strong> attribute for
+        a rare case when it can be omitted.</p>
       </attribute>
 
       <attribute name="userTable" required="true">
@@ -310,11 +330,12 @@
     DataSource Realm HOW-TO</a> for more information on setting up container
     managed security using the DataSource Database Realm component.</p>
 
+  </subsection>
 
-    <h3>JNDI Directory Realm (org.apache.catalina.realm.JNDIRealm)</h3>
 
+  <subsection name="JNDI Directory Realm - org.apache.catalina.realm.JNDIRealm">
 
-    <p>The <strong>JNDI Directory Realm</strong> connects Catalina to
+    <p>The <strong>JNDI Directory Realm</strong> connects Tomcat to
     an LDAP Directory, accessed through an appropriate JNDI driver,
     that stores usernames, passwords, and their associated
     roles. Changes to the directory are immediately reflected in the
@@ -457,7 +478,7 @@
         <p>The base directory entry for performing role searches. If not
         specified the top-level element in the directory context will be used.
         If specified it may optionally include pattern replacements
-        "{0}".."{n}" corrosponding to the name parts of the
+        "{0}".."{n}" corresponding to the name parts of the
         user's distinguished name (as returned by
         <code>javax.naming.Name.get()</code>).</p>
       </attribute>
@@ -467,25 +488,51 @@
         directory entries found by a role search. In addition you can
         use the <code>userRoleName</code> property to specify the name
         of an attribute, in the user's entry, containing additional
-        role names.  If <code>roleName</code> is not specified a role
+        role names.</p>
+        <p>If <code>roleName</code> is not specified a role
         search does not take place, and roles are taken only from the
         user's entry.</p>
       </attribute>
 
+      <attribute name="roleNested" required="false">
+        <p>Set to <code>true</code> if you want to nest roles into roles.
+        When a role search is performed and the value of this property is
+        <code>true</code>, the search will be repeated recursively to find
+        all the roles that belong to the user either directly or indirectly.
+        If not specified, the default value of <code>false</code> is used.</p>
+      </attribute>
+
       <attribute name="roleSearch" required="false">
         <p>The LDAP filter expression used for performing role
-        searches.  Use <code>{0}</code> to substitute the
-        distinguished name (DN) of the user, and/or <code>{1}</code> to
-        substitute the username. If not specified a role search does
-        not take place and roles are taken only from the attribute in
-        the user's entry specified by the <code>userRoleName</code>
-        property.</p>
+        searches.</p>
+
+        <p>Use <code>{0}</code> to substitute the distinguished name (DN)
+        of the user, and/or <code>{1}</code> to substitute the username,
+        and/or <code>{2}</code> for the value of an attribute from the
+        user's directory entry, of the authenticated user.
+        The name of the attribute that provides the value for <code>{2}</code>
+        is configured by the <code>userRoleAttribute</code> property.</p>
+
+        <p>When <code>roleNested</code> property is <code>true</code>,
+        this filter expression will be also used to recursively search for
+        other roles, which indirectly belong to this user. To find the
+        roles that match the newly found role, the following values
+        are used:
+        <code>{0}</code> is substituted by the distinguished name of the newly
+        found role, and both <code>{1}</code> and <code>{2}</code> are
+        substituted by the name of the role (see the <code>roleName</code>
+        property). The <code>userRoleAttribute</code> property is not
+        applicable to this search.</p>
+
+        <p>If this property is not specified, a role search does not take
+        place and roles are taken only from the attribute in the user's entry
+        specified by the <code>userRoleName</code> property.</p>
       </attribute>
 
       <attribute name="roleSearchAsUser" required="false">
         <p> When searching for user roles, should the search be performed as the
         user currently being authenticated? If false,
-        <code>connectionName</code>} and <code>connectionPassword</code> will be
+        <code>connectionName</code> and <code>connectionPassword</code> will be
         used if specified, else an anonymous. If not specified, the default
         value of <code>false</code> is used. Note that when accessing the
         directory using delegated credentials, this attribute is always ignored
@@ -572,6 +619,16 @@
         search.</p>
       </attribute>
 
+      <attribute name="userRoleAttribute" required="false">
+        <p>The name of an attribute in the user's directory entry
+        containing the value that you wish to use when you search for
+        roles. This is especially useful for RFC 2307 where
+        the role memberUid can be the <code>uid</code> or the
+        <code>uidNumber</code> of the user. This value will be
+        marked as <code>{2}</code> in your role search filter expression.
+        This value will NOT be available for nested role searches.</p>
+      </attribute>
+
       <attribute name="userSearch" required="false">
         <p>The LDAP filter expression to use when searching for a
         user's directory entry, with <code>{0}</code> marking where
@@ -605,14 +662,16 @@
     information on setting up container managed security using the
     JNDI Directory Realm component.</p>
 
+  </subsection>
+
 
-    <h3>UserDatabase Realm (org.apache.catalina.realm.UserDatabaseRealm)</h3>
+  <subsection name="UserDatabase Realm - org.apache.catalina.realm.UserDatabaseRealm">
 
     <p>The <strong>UserDatabase Realm</strong> is a Realm implementation
     that is based on a UserDatabase resource made available through the global
     JNDI resources configured for this Tomcat instance.</p>
 
-    <p>The Memory Based Realm implementation supports the following
+    <p>The UserDatabase Realm implementation supports the following
     additional attributes:</p>
 
     <attributes>
@@ -631,8 +690,8 @@
       </attribute>
 
       <attribute name="resourceName" required="true">
-        <p>The name of the resource that this realm will use for user, password
-        and role information.</p>
+        <p>The name of the global <code>UserDatabase</code> resource
+        that this realm will use for user, password and role information.</p>
       </attribute>
 
       <attribute name="X509UsernameRetrieverClassName" required="false">
@@ -652,7 +711,10 @@
     <a href="../jndi-resources-howto.html">JNDI resources how-to</a> for more
     information on how to configure a UserDatabase resource.</p>
 
-    <h3>Memory Based Realm (org.apache.catalina.realm.MemoryRealm)</h3>
+  </subsection>
+
+
+  <subsection name="Memory Based Realm - org.apache.catalina.realm.MemoryRealm">
 
     <p>The <strong>Memory Based Realm</strong> is a simple Realm implementation
     that reads user information from an XML format, and represents it as a
@@ -733,7 +795,10 @@
     information on setting up container managed security using the
     Memory Based Realm component.</p>
 
-    <h3>JAAS Realm (org.apache.catalina.realm.JAASRealm)</h3>
+  </subsection>
+
+
+  <subsection name="JAAS Realm - org.apache.catalina.realm.JAASRealm">
 
     <p><strong>JAASRealm</strong> is an implementation of the Tomcat
     <code>Realm</code> interface that authenticates users through the Java
@@ -819,7 +884,10 @@
     Guide</a> for more information on setting up container managed security
     using the JAAS Realm component.</p>
 
-    <h3>Combined Realm (org.apache.catalina.realm.CombinedRealm)</h3>
+  </subsection>
+
+
+  <subsection name="Combined Realm - org.apache.catalina.realm.CombinedRealm">
 
     <p><strong>CombinedRealm</strong> is an implementation of the Tomcat
     <code>Realm</code> interface that authenticates users through one or more
@@ -843,7 +911,10 @@
     Guide</a> for more information on setting up container managed security
     using the CombinedRealm component.</p>
 
-    <h3>LockOut Realm (org.apache.catalina.realm.LockOutRealm)</h3>
+  </subsection>
+
+
+  <subsection name="LockOut Realm - org.apache.catalina.realm.LockOutRealm">
 
     <p><strong>LockOutRealm</strong> is an implementation of the Tomcat
     <code>Realm</code> interface that extends the CombinedRealm to provide lock
@@ -901,7 +972,6 @@
 
   </subsection>
 
-
 </section>
 
 
diff --git a/webapps/docs/config/systemprops.xml b/webapps/docs/config/systemprops.xml
index 9751a8c..3bc0d15 100644
--- a/webapps/docs/config/systemprops.xml
+++ b/webapps/docs/config/systemprops.xml
@@ -276,14 +276,14 @@
       <p>The default value of this system property is <code>false</code>.</p>
       <p>If this is <code>true</code> the default values will be changed for:
       <ul>
-      <li><code>org.apache.catalina.core.ApplicationContext.GET_RESOURCE_REQUIRE_SLASH</code></li>
-      <li><code>org.apache.catalina.core.ApplicationDispatcher.WRAP_SAME_OBJECT</code></li>
-      <li><code>org.apache.catalina.core.StandardHostValve.ACCESS_SESSION</code></li>
-      <li><code>org.apache.catalina.session.StandardSession.ACTIVITY_CHECK</code></li>
-      <li><code>org.apache.catalina.session.StandardSession.LAST_ACCESS_AT_START</code></li>
-      <li><code>org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES</code></li>
-      <li><code>org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR</code></li>
-      <li><code>org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING</code></li>
+      <li><code>org.apache.catalina.core.<br/>ApplicationContext.GET_RESOURCE_REQUIRE_SLASH</code></li>
+      <li><code>org.apache.catalina.core.<br/>ApplicationDispatcher.WRAP_SAME_OBJECT</code></li>
+      <li><code>org.apache.catalina.core.<br/>StandardHostValve.ACCESS_SESSION</code></li>
+      <li><code>org.apache.catalina.session.<br/>StandardSession.ACTIVITY_CHECK</code></li>
+      <li><code>org.apache.catalina.session.<br/>StandardSession.LAST_ACCESS_AT_START</code></li>
+      <li><code>org.apache.tomcat.util.http.<br/>ServerCookie.ALWAYS_ADD_EXPIRES</code></li>
+      <li><code>org.apache.tomcat.util.http.<br/>ServerCookie.FWD_SLASH_IS_SEPARATOR</code></li>
+      <li><code>org.apache.tomcat.util.http.<br/>ServerCookie.STRICT_NAMING</code></li>
       <li>The <code>resourceOnlyServlets</code> attribute of any
           <a href="context.html">Context</a> element.</li>
       <li>The <code>tldNamespaceAware</code> attribute of any
@@ -460,7 +460,7 @@
          <code>-Dorg.apache.juli.formatter=org.apache.juli.OneLineFormatter</code></p>
     </property>
 
-    <property name="org.apache.juli.AsyncOverflowDropType">
+    <property name="org.apache.juli. AsyncOverflowDropType">
       <p>When the memory limit of records has been reached the system needs to determine what action to take.
          Currently there are three actions that can be taken:
       </p>
@@ -473,7 +473,7 @@
       <p>The default value is <code>1</code> (OVERFLOW_DROP_LAST).</p>
     </property>
 
-    <property name="org.apache.juli.AsyncMaxRecordCount">
+    <property name="org.apache.juli. AsyncMaxRecordCount">
       <p>The max number of log records that the async logger will keep in memory. When this limit is reached and a new record is being logged by the
          JULI framework the system will take an action based on the <code>org.apache.juli.AsyncOverflowDropType</code> setting.</p>
       <p>The default value is <code>10000</code> records.
@@ -481,14 +481,14 @@
       </p>
     </property>
 
-    <property name="org.apache.juli.AsyncLoggerPollInterval">
+    <property name="org.apache.juli. AsyncLoggerPollInterval">
       <p>The poll interval in milliseconds for the asynchronous logger thread in milliseconds.
          If the log queue is empty, the async thread will issue a poll(poll interval)
          in order to not wake up to often.</p>
       <p>The default value is <code>1000</code> milliseconds.</p>
     </property>
 
-    <property name="org.apache.juli.logging.UserDataHelper.CONFIG">
+    <property name="org.apache.juli.logging. UserDataHelper.CONFIG">
       <p>The type of logging to use for errors generated by invalid input data.
          The options are: <code>DEBUG_ALL</code>, <code>INFO_THEN_DEBUG</code>,
          <code>INFO_ALL</code> and <code>NONE</code>. When
@@ -506,7 +506,7 @@
          system in later versions.</p>
     </property>
 
-    <property name="org.apache.juli.logging.UserDataHelper.SUPPRESSION_TIME">
+    <property name="org.apache.juli.logging. UserDataHelper.SUPPRESSION_TIME">
       <p>When using <code>INFO_THEN_DEBUG</code> for
          <code>org.apache.juli.logging.UserDataHelper.CONFIG</code> this system
          property controls how long messages are logged at DEBUG after a message
@@ -523,6 +523,39 @@
 
 </section>
 
+<section name="JAR Scanning">
+
+  <properties>
+    <property name="tomcat.util.scan. DefaultJarScanner.jarsToSkip">
+      <p>The comma-separated list of filenames of JARs that Tomcat will not scan
+         for configuration information when using the
+         <a href="jar-scanner.html">JarScanner</a> functionality. Note that
+         there are additional system properties that enable JARs to be excluded
+         from specific scans rather than all scans.</p>
+      <p>The coded default is that no JARs are skipped however the system
+         property is set in a default Tomcat installation via the
+         <code>$CATALINA_BASE/conf/catalina.properties</code> file.</p>
+    </property>
+
+    <property name="org.apache.catalina.startup. ContextConfig.jarsToSkip">
+      <p>The comma-separated list of additional filenames of JARs that Tomcat
+         will not scan for Servlet 3.0 pluggability features.</p>
+      <p>The coded default is that no JARs are skipped however the system
+         property is set in a default Tomcat installation via the
+         <code>$CATALINA_BASE/conf/catalina.properties</code> file.</p>
+    </property>
+
+    <property name="org.apache.catalina.startup. TldConfig.jarsToSkip">
+      <p>The comma-separated list of additional filenames of JARs that Tomcat
+         will not scan for TLDs.</p>
+      <p>The coded default is that no JARs are skipped however the system
+         property is set in a default Tomcat installation via the
+         <code>$CATALINA_BASE/conf/catalina.properties</code> file.</p>
+    </property>
+  </properties>
+
+</section>
+
 <section name="Other">
 
   <properties>
@@ -610,6 +643,11 @@
       <p>If not specified, the default value of <code>false</code> will be used.</p>
     </property>
 
+    <property name="org.apache.catalina.startup. RealmRuleSet.MAX_NESTED_REALM_LEVELS">
+      <p>The CombinedRealm allows nested Realms. This property controls the
+      maximum permitted number of levels of nesting.</p>
+      <p>If not specified, the default value of <code>3</code> will be used.</p>
+    </property>
 
   </properties>
 
diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml
index 897c627..e3bdcec 100644
--- a/webapps/docs/config/valve.xml
+++ b/webapps/docs/config/valve.xml
@@ -268,24 +268,24 @@
     </p>
 
     <p>All formats supported by SimpleDateFormat are allowed in <code>%{xxx}t</code>.
-    In addition the following extensions have been added:
+    In addition the following extensions have been added:</p>
     <ul>
     <li><b><code>sec</code></b> - number of seconds since the epoch</li>
     <li><b><code>msec</code></b> - number of milliseconds since the epoch</li>
     <li><b><code>msec_frac</code></b> - millisecond fraction</li>
     </ul>
-    These formats can not be mixed with SimpleDateFormat formats in the same format
+    <p>These formats can not be mixed with SimpleDateFormat formats in the same format
     token.</p>
 
     <p>Furthermore one can define whether to log the timestamp for the request start
-    time or the response finish time:
+    time or the response finish time:</p>
     <ul>
     <li><b><code>begin</code></b> or prefix <b><code>begin:</code></b> chooses
     the request start time</li>
     <li><b><code>end</code></b> or prefix <b><code>end:</code></b> chooses
     the response finish time</li>
     </ul>
-    By adding multiple <code>%{xxx}t</code> tokens to the pattern, one can
+    <p>By adding multiple <code>%{xxx}t</code> tokens to the pattern, one can
     also log both timestamps.</p>
 
     <p>The shorthand pattern <code>pattern="common"</code>
@@ -831,7 +831,7 @@
 
       <attribute name="cache" required="false">
         <p>Should we cache authenticated Principals if the request is part of an
-        HTTP session? If not specified, the default value of <code>true</code>
+        HTTP session? If not specified, the default value of <code>false</code>
         will be used.</p>
       </attribute>
 
@@ -847,12 +847,6 @@
         <strong>org.apache.catalina.authenticator.DigestAuthenticator</strong>.</p>
       </attribute>
 
-      <attribute name="cnonceCacheSize" required="false">
-        <p>To protect against replay attacks, the DIGEST authenticator tracks
-        client nonce and nonce count values. This attribute controls the size
-        of that cache. If not specified, the default value of 1000 is used.</p>
-      </attribute>
-
       <attribute name="disableProxyCaching" required="false">
         <p>Controls the caching of pages that are protected by security
         constraints. Setting this to <code>false</code> may help work around
@@ -870,6 +864,21 @@
         and/or across a cluster.</p>
       </attribute>
 
+      <attribute name="nonceCacheSize" required="false">
+        <p>To protect against replay attacks, the DIGEST authenticator tracks
+        server nonce and nonce count values. This attribute controls the size
+        of that cache. If not specified, the default value of 1000 is used.</p>
+      </attribute>
+
+      <attribute name="nonceCountWindowSize" required="false">
+        <p>Client requests may be processed out of order which in turn means
+        that the nonce count values may be processed out of order. To prevent
+        authentication failures when nonce counts are presented out of order
+        the authenticator tracks a window of nonce count values. This attribute
+        controls how big that window is. If not specified, the default value of
+        100 is used.</p>
+      </attribute>
+
       <attribute name="nonceValidity" required="false">
         <p>The time, in milliseconds, that a server generated nonce will be
         considered valid for use in authentication. If not specified, the
@@ -1152,6 +1161,18 @@
 
     <attributes>
 
+      <attribute name="alwaysUseSession" required="false">
+        <p>Should a session always be used once a user is authenticated? This
+        may offer some performance benefits since the session can then be used
+        to cache the authenticated Principal, hence removing the need to
+        authenticate the user on every request. This will also help with clients
+        that assume that the server will cache the authenticated user. However
+        there will also be the performance cost of creating and GC'ing the
+        session. For an alternative solution see
+        <code>noKeepAliveUserAgents</code>. If not set, the default value of
+        <code>false</code> will be used.</p>
+      </attribute>
+
       <attribute name="cache" required="false">
         <p>Should we cache authenticated Principals if the request is part of an
         HTTP session? If not specified, the default value of <code>true</code>
@@ -1187,6 +1208,25 @@
         <code>com.sun.security.jgss.krb5.accept</code> is used.</p>
       </attribute>
 
+      <attribute name="noKeepAliveUserAgents" required="false">
+        <p>Some clients (not most browsers) expect the server to cache the
+        authenticated user information for a connection and do not resend the
+        credentials with every request. Tomcat will not do this unless an HTTP
+        session is available. A session will be availble if either the
+        application creates one or if <code>alwaysUseSession</code> is enabled
+        for this Authenticator.</p>
+        <p>As an alternative to creating a session, this attribute may be used
+        to define the user agents for which HTTP keep-alive is disabled. This
+        means that a connection will only used for a single request and hence
+        there is no ability to cache authenticated user information per
+        connection. There will be a performance cost in disabling HTTP
+        keep-alive.</p>
+        <p>The attribute should be a regular expression that matches the entire
+        user-agent string, e.g. <code>.*Chrome.*</code>. If not specified, no
+        regular expression will be defined and no user agents will have HTTP
+        keep-alive disabled.</p>
+      </attribute>
+
       <attribute name="securePagesWithPragma" required="false">
         <p>Controls the caching of pages that are protected by security
         constraints. Setting this to <code>false</code> may help work around
@@ -1444,9 +1484,11 @@
     indicate that the thread that is processing it is stuck.</p>
     <p>When such a request is detected, the current stack trace of its thread is written
     to Tomcat log with a WARN level.</p>
-    <p>The IDs of the stuck threads are available through JMX in the
-    <code>stuckThreadIds</code> attribute. The JVM Thread MBean can then be used to
-    retrieve other information about each stuck thread (name, stack trace...).</p>
+    <p>The IDs and names of the stuck threads are available through JMX in the
+    <code>stuckThreadIds</code> and <code>stuckThreadNames</code> attributes.
+    The IDs can be used with the standard Threading JVM MBean
+    (<code>java.lang:type=Threading</code>) to retrieve other information
+    about each stuck thread.</p>
 
   </subsection>
 
diff --git a/webapps/docs/jasper-howto.xml b/webapps/docs/jasper-howto.xml
index 826c051..a9ab663 100644
--- a/webapps/docs/jasper-howto.xml
+++ b/webapps/docs/jasper-howto.xml
@@ -342,7 +342,7 @@ are automatically compiled as part of the build process.
 </p>
 
 <p>
-At the jasper2 task you can use the option <code>addWebXmlMappings</code> for
+At the jasper task you can use the option <code>addWebXmlMappings</code> for
 automatic merge the <code>${webapp.path}/WEB-INF/generated_web.xml</code>
 with the current web application deployment descriptor at
 <code>${webapp.path}/WEB-INF/web.xml</code>. When you want to use Java 6
diff --git a/webapps/docs/jndi-datasource-examples-howto.xml b/webapps/docs/jndi-datasource-examples-howto.xml
index 654b826..2762aa0 100644
--- a/webapps/docs/jndi-datasource-examples-howto.xml
+++ b/webapps/docs/jndi-datasource-examples-howto.xml
@@ -339,8 +339,8 @@ select id, foo, bar from testdata
 <p>That JSP page makes use of <a href="http://java.sun.com/products/jsp/jstl">JSTL</a>'s
 SQL and Core taglibs. You can get it from
 <a href="http://tomcat.apache.org/taglibs/standard/">Apache Tomcat Taglibs - Standard Tag Library</a>
-project &#x2014; just make sure you get a 1.1.x release. Once you have JSTL,
-copy <code>jstl.jar</code> and <code>standard.jar</code> to your web app's
+project &#x2014; just make sure you get a 1.1.x or later release. Once you have
+JSTL, copy <code>jstl.jar</code> and <code>standard.jar</code> to your web app's
 <code>WEB-INF/lib</code> directory.
 
 </p>
diff --git a/webapps/docs/manager-howto.xml b/webapps/docs/manager-howto.xml
index 86e2510..c8645df 100644
--- a/webapps/docs/manager-howto.xml
+++ b/webapps/docs/manager-howto.xml
@@ -236,6 +236,8 @@ the host and port appropriately for your installation.</p>
     application, specify "/".  <strong>NOTE</strong> -
     It is not possible to perform administrative commands on the
     Manager application itself.</li>
+<li><strong>version</strong> - The version of this web application as used by
+    the parallel deployment feature,</li>
 <li><strong>war</strong> - URL of a web application archive (WAR) file,
     pathname of a directory which contains the web application, or a
     Context configuration ".xml" file.  You can use URLs in any of the
@@ -298,8 +300,8 @@ including a Context configuration XML file in
 <li><code>update</code>: When set to true, any existing update will be
     undeployed first. The default value is set to false.</li>
 <li><code>tag</code>: Specifying a tag name, this allows associating the
-    deployed webapp with a version number. The application version can
-    be later redeployed when needed using only the tag.</li>
+    deployed webapp with a tag or label. If the web application is undeployed,
+    it can be later redeployed when needed using only the tag.</li>
 </ul>
 
 <p><strong>NOTE</strong> - This command is the logical
@@ -344,9 +346,9 @@ This command is the logical opposite of the <code>/undeploy</code> command.</p>
 
 <p>There are a number of different ways the deploy command can be used.</p>
 
-<h3>Deploy a version of a previously deployed webapp</h3>
+<h3>Deploy a previously deployed webapp</h3>
 
-<p>This can be used to deploy a previous version of a web application, which
+<p>This can be used to deploy a previously deployed web application, which
 has been deployed using the <code>tag</code> attribute. Note that the work
 directory for the Manager webapp will contain the previously deployed WARs;
 removing it would make the deployment fail.</p>
diff --git a/webapps/docs/monitoring.xml b/webapps/docs/monitoring.xml
index 611a866..1c651bb 100644
--- a/webapps/docs/monitoring.xml
+++ b/webapps/docs/monitoring.xml
@@ -90,7 +90,7 @@ controlRole tomcat
   <section name="Manage Tomcat with JMX remote Ant Tasks">
    <p>To simplify JMX usage with Ant 1.6.x, a set of tasks is provided that may
    be used with antlib.</p>
-   <p><b>antlib</b>Copy your catalina-ant.jar from $CATALINA_HOME/lib to $ANT_HOME/lib.</p>
+   <p><b>antlib</b>: Copy your catalina-ant.jar from $CATALINA_HOME/lib to $ANT_HOME/lib.</p>
    <p>The following example shows the JMX Accessor usage:</p>
    <table border="1">
    <tr><td><p><pre>
@@ -193,7 +193,7 @@ controlRole tomcat
    <p><b>import:</b> Import the JMX Accessor Project with
    <em><import file="${CATALINA.HOME}/bin/catalina-tasks.xml" /></em> and
    reference the tasks with <em>jmxOpen</em>, <em>jmxSet</em>, <em>jmxGet</em>,
-    <em>jmxQuery</em>, <em>jmxInvoke</em>,<em>jmxEquals</em> and <em>jmxCondition</em>. </p>
+   <em>jmxQuery</em>, <em>jmxInvoke</em>, <em>jmxEquals</em> and <em>jmxCondition</em>.</p>
 
   </section>
 
@@ -1126,5 +1126,44 @@ Wait for server connection and that cluster backup node is accessible<br/>
 
 </section>
 
+  <section name="Using the JMXProxyServlet">
+
+    <p>
+      Tomcat offers an alternative to using remote (or even local) JMX
+      connections while still giving you access to everything JMX has to offer:
+      Tomcat's
+      <a href="api/org/apache/catalina/manager/JMXProxyServlet.html">JMXProxyServlet</a>.
+    </p>
+    
+    <p>
+      The JMXProxyServlet allows a client to issue JMX queries via an HTTP
+      interface. This technique offers the following advantages over using
+      JMX directly from a client program:
+    </p>
+
+    <ul>
+      <li>You don't have to launch a full JVM and make a remote JMX connection
+      just to ask for one small piece of data from a runing server</li>
+      <li>You don't have to know how to work with JMX connections</li>
+      <li>You don't need any of the complex configuration covered in the rest
+      of this page</li>
+      <li>Your client program does not have to be written in Java</li>
+    </ul>
+
+    <p>
+      A perfect example of JMX overkill can be seen in the case of popular
+      server-monitoring software such as Nagios or Ichinga: if you want to
+      monitor 10 items via JMX, you will have to launch 10 JVMs, make 10 JMX
+      connections, and then shut them all down every few minutes. With the
+      JMXProxyServlet, you can make 10 HTTP connections and be done with it.
+    </p>
+    
+    <p>
+      You can find out more information about the JMXProxyServlet in the
+      documentation for the 
+      <a href="manager-howto.html#Using_the_JMX_Proxy_Servlet">Tomcat
+      manager</a>.
+    </p>
+  </section>
 </body>
 </document>
diff --git a/webapps/docs/realm-howto.xml b/webapps/docs/realm-howto.xml
index 5a75139..b662fbf 100644
--- a/webapps/docs/realm-howto.xml
+++ b/webapps/docs/realm-howto.xml
@@ -642,13 +642,15 @@ find the names of roles associated with the authenticated user:</p>
 <li><strong>roleSearch</strong> - the LDAP search filter for
     selecting role entries. It optionally includes pattern
     replacements "{0}" for the distinguished name and/or "{1}" for the
-    username of the authenticated user.</li>
+    username and/or "{2}" for an attribute from user's directory entry,
+    of the authenticated user. Use <strong>userRoleAttribute</strong> to
+    specify the name of the attribute that provides the value for "{2}".</li>
 
 <li><strong>roleName</strong> - the attribute in a role entry
      containing the name of that role.</li>
 
 <li><strong>roleNested</strong> - enable nested roles. Set to
-     <code>true</code> if you want to nest roles in roles. If configured
+     <code>true</code> if you want to nest roles in roles. If configured, then
      every newly found roleName and distinguished
      Name will be recursively tried for a new role search.
      The default value is <code>false</code>.</li>
diff --git a/webapps/docs/setup.xml b/webapps/docs/setup.xml
index 3bdc941..36fe493 100644
--- a/webapps/docs/setup.xml
+++ b/webapps/docs/setup.xml
@@ -143,11 +143,9 @@
        information. In particular, the <code>-debug</code> option is useful
        to debug issues running jsvc.</p>
 
-    <p>The file <code>
-       $CATALINA_HOME/bin/commons-daemon-1.0.x-native-src/unix/native/Tomcat5.sh
-       </code> can be used as a template for starting Tomcat automatically at
-       boot time from <code>/etc/init.d</code>. The file is currently setup for
-       running Tomcat 5.5.x, so it will be necessary to edit it a little.</p>
+    <p>The file <code>$CATALINA_HOME/bin/daemon.sh</code> can be used as a
+       template for starting Tomcat automatically at boot time from
+       <code>/etc/init.d</code> with jsvc.</p>
 
     <p>Note that the Commons-Daemon JAR file must be on your runtime classpath
        to run Tomcat in this manner.  The Commons-Daemon JAR file is in the
diff --git a/webapps/docs/ssi-howto.xml b/webapps/docs/ssi-howto.xml
index e7dc487..a0b8ffa 100644
--- a/webapps/docs/ssi-howto.xml
+++ b/webapps/docs/ssi-howto.xml
@@ -99,7 +99,7 @@ directives will expire. Default behaviour is for all SSI directives to be
 evaluated for every request.</li>
 <li><strong>isVirtualWebappRelative</strong> - Should "virtual" SSI directive
 paths be interpreted as relative to the context root, instead of the server
-root? (0=false, 1=true) Default 0 (false).</li>
+root? Default false.</li>
 <li><strong>inputEncoding</strong> - The encoding to be assumed for SSI
 resources if one cannot be determined from the resource itself. Default is
 the default platform encoding.</li>
@@ -129,7 +129,7 @@ directives will expire. Default behaviour is for all SSI directives to be
 evaluated for every request.</li>
 <li><strong>isVirtualWebappRelative</strong> - Should "virtual" SSI directive
 paths be interpreted as relative to the context root, instead of the server
-root? (0=false, 1=true) Default 0 (false).</li>
+root? Default false.</li>
 <li><strong>allowExec</strong> - Is the exec command enabled? Default is
 false.</li>
 </ul>
diff --git a/webapps/docs/ssl-howto.xml b/webapps/docs/ssl-howto.xml
index 68bb636..54adb37 100644
--- a/webapps/docs/ssl-howto.xml
+++ b/webapps/docs/ssl-howto.xml
@@ -343,11 +343,13 @@ sources like "/dev/urandom" that will allow quicker starts of Tomcat.
 <code>$CATALINA_BASE</code> represents the base directory for the
 Tomcat instance.  An example <code><Connector></code> element
 for an SSL connector is included in the default <code>server.xml</code>
-file installed with Tomcat.  For JSSE, it should look something like this:</p>
+file installed with Tomcat.  To configure an SSL connector that uses JSSE, you
+will need to remove the comments and edit it so it looks something like
+this:</p>
 <source>
 <-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
-<!--
 <Connector
+           protocol="HTTP/1.1"
            port="8443" maxThreads="200"
            scheme="https" secure="true" SSLEnabled="true"
            keystoreFile="${user.home}/.keystore" keystorePass="changeit"
@@ -355,19 +357,19 @@ file installed with Tomcat.  For JSSE, it should look something like this:</p>
 -->
 </source>
 <p>
-  The example above will throw an error if you have the APR and the Tomcat Native libraries in your path,
-  as Tomcat will try to use the APR connector. The APR connector uses different attributes for
-  SSL keys and certificates. An example of an APR configuration is:
+  The example above will throw an error if you have the APR and the Tomcat
+  Native libraries in your path, as Tomcat will try to use the APR connector.
+  The APR connector uses different attributes for many SSL settings,
+  particularly keys and certificates. An example of an APR configuration is:
 <source>
 <-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
-<!--
 <Connector
+           protocol="HTTP/1.1"
            port="8443" maxThreads="200"
            scheme="https" secure="true" SSLEnabled="true"
            SSLCertificateFile="/usr/local/ssl/server.crt"
            SSLCertificateKeyFile="/usr/local/ssl/server.pem"
-           clientAuth="optional" SSLProtocol="TLSv1"/>
--->
+           SSLVerifyClient="optional" SSLProtocol="TLSv1"/>
 </source>
 </p>
 
diff --git a/webapps/docs/tomcat-docs.xsl b/webapps/docs/tomcat-docs.xsl
index bf58e48..45fe2eb 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 1200139 2011-11-10 04:19:11Z kkolinko $ -->
+<!-- $Id: tomcat-docs.xsl 1371339 2012-08-09 17:48:18Z schultz $ -->
 
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="1.0">
@@ -87,6 +87,11 @@
             code {background-color:rgb(224,255,255);padding:0 0.1em;}
             code.attributeName, code.propertyName {background-color:transparent;}
         </style>
+        <style type="text/css">
+            .wrapped-source code { display: block; background-color: transparent; }
+            .wrapped-source div { margin: 0 0 0 1.25em; }
+            .wrapped-source p { margin: 0 0 0 1.25em; text-indent: -1.25em; }
+        </style>
     </head>
 
     <body bgcolor="{$body-bg}" text="{$body-fg}" link="{$body-link}"
@@ -326,9 +331,22 @@
           <td bgcolor="{$source-color}" width="1">
             <img src="{$void}" alt="" width="1" height="1" vspace="0" hspace="0" border="0"/>
           </td>
+    <xsl:choose>
+      <xsl:when test="@wrapped='true'">
+          <td bgcolor="#ffffff" height="1">
+            <div class="wrapped-source">
+            <code>
+              <xsl:apply-templates />
+            </code>
+            </div>
+          </td>
+      </xsl:when>
+      <xsl:otherwise>
           <td bgcolor="#ffffff" height="1"><pre>
             <xsl:value-of select="."/>
           </pre></td>
+      </xsl:otherwise>
+    </xsl:choose>
           <td bgcolor="{$source-color}" width="1">
             <img src="{$void}" alt="" width="1" height="1" vspace="0" hspace="0" border="0"/>
           </td>
@@ -349,6 +367,18 @@
   </xsl:template>
 
 
+  <!-- Process a wrapped source code example - indent -->
+  <xsl:template match="source//indent">
+    <div><xsl:apply-templates /></div>
+  </xsl:template>
+
+
+  <!-- Process a wrapped source code example - outdent -->
+  <xsl:template match="source//outdent">
+    <p><xsl:apply-templates /></p>
+  </xsl:template>
+
+
   <!-- Process an attributes list with nested attribute elements -->
   <xsl:template match="attributes">
     <table border="1" cellpadding="5">
diff --git a/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java b/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
index 4ab722a..f701a92 100644
--- a/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
+++ b/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
@@ -36,9 +36,8 @@ public class CompressionResponseStream extends ServletOutputStream {
     /**
      * Construct a servlet output stream associated with the specified Response.
      *
-     * @param response The associated response
-     * @param response
-     * @param originalOutput
+     * @param responseWrapper The associated response wrapper
+     * @param originalOutput the output stream
      */
     public CompressionResponseStream(
             CompressionServletResponseWrapper responseWrapper,
diff --git a/webapps/examples/WEB-INF/classes/websocket/chat/ChatWebSocketServlet.java b/webapps/examples/WEB-INF/classes/websocket/chat/ChatWebSocketServlet.java
index c87b958..4b06586 100644
--- a/webapps/examples/WEB-INF/classes/websocket/chat/ChatWebSocketServlet.java
+++ b/webapps/examples/WEB-INF/classes/websocket/chat/ChatWebSocketServlet.java
@@ -23,6 +23,8 @@ import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.catalina.websocket.MessageInbound;
 import org.apache.catalina.websocket.StreamInbound;
 import org.apache.catalina.websocket.WebSocketServlet;
@@ -44,7 +46,8 @@ public class ChatWebSocketServlet extends WebSocketServlet {
             new CopyOnWriteArraySet<ChatMessageInbound>();
 
     @Override
-    protected StreamInbound createWebSocketInbound(String subProtocol) {
+    protected StreamInbound createWebSocketInbound(String subProtocol,
+            HttpServletRequest request) {
         return new ChatMessageInbound(connectionIds.incrementAndGet());
     }
 
diff --git a/webapps/examples/WEB-INF/classes/websocket/echo/EchoMessage.java b/webapps/examples/WEB-INF/classes/websocket/echo/EchoMessage.java
index 1806dd5..8a1d981 100644
--- a/webapps/examples/WEB-INF/classes/websocket/echo/EchoMessage.java
+++ b/webapps/examples/WEB-INF/classes/websocket/echo/EchoMessage.java
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
 
 import org.apache.catalina.websocket.MessageInbound;
 import org.apache.catalina.websocket.StreamInbound;
@@ -59,7 +60,8 @@ public class EchoMessage extends WebSocketServlet {
 
 
     @Override
-    protected StreamInbound createWebSocketInbound(String subProtocol) {
+    protected StreamInbound createWebSocketInbound(String subProtocol,
+            HttpServletRequest request) {
         return new EchoMessageInbound(byteBufSize,charBufSize);
     }
 
diff --git a/webapps/examples/WEB-INF/classes/websocket/echo/EchoStream.java b/webapps/examples/WEB-INF/classes/websocket/echo/EchoStream.java
index d6e7a57..a6acd7c 100644
--- a/webapps/examples/WEB-INF/classes/websocket/echo/EchoStream.java
+++ b/webapps/examples/WEB-INF/classes/websocket/echo/EchoStream.java
@@ -20,6 +20,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.catalina.websocket.StreamInbound;
 import org.apache.catalina.websocket.WebSocketServlet;
 import org.apache.catalina.websocket.WsOutbound;
@@ -30,7 +32,8 @@ public class EchoStream extends WebSocketServlet {
     private static final long serialVersionUID = 1L;
 
     @Override
-    protected StreamInbound createWebSocketInbound(String subProtocol) {
+    protected StreamInbound createWebSocketInbound(String subProtocol,
+            HttpServletRequest request) {
         return new EchoStreamInbound();
     }
 
diff --git a/webapps/examples/WEB-INF/classes/websocket/snake/SnakeWebSocketServlet.java b/webapps/examples/WEB-INF/classes/websocket/snake/SnakeWebSocketServlet.java
index d311cf8..bf7e2be 100644
--- a/webapps/examples/WEB-INF/classes/websocket/snake/SnakeWebSocketServlet.java
+++ b/webapps/examples/WEB-INF/classes/websocket/snake/SnakeWebSocketServlet.java
@@ -30,6 +30,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
 
 import org.apache.catalina.websocket.MessageInbound;
 import org.apache.catalina.websocket.StreamInbound;
@@ -148,7 +149,8 @@ public class SnakeWebSocketServlet extends WebSocketServlet {
     }
 
     @Override
-    protected StreamInbound createWebSocketInbound(String subProtocol) {
+    protected StreamInbound createWebSocketInbound(String subProtocol,
+            HttpServletRequest request) {
         return new SnakeMessageInbound(connectionIds.incrementAndGet());
     }
 
diff --git a/webapps/examples/jsp/cal/login.html b/webapps/examples/jsp/cal/login.html
index 4f51a7b..2c4aa55 100644
--- a/webapps/examples/jsp/cal/login.html
+++ b/webapps/examples/jsp/cal/login.html
@@ -39,8 +39,8 @@
     </form>
 <hr>
 <font size=3 color="red"> Note: This application does not implement the complete
-functionality of a typical calendar application. It demostartes a way JSP can be
-used with html tables and forms.</font>
+functionality of a typical calendar application. It demonstrates a way JSP can
+be used with html tables and forms.</font>
 
 </center>
 </body>
diff --git a/webapps/examples/jsp/jsp2/jspx/svgexample.html b/webapps/examples/jsp/jsp2/jspx/svgexample.html
index 20ce06b..2879a25 100644
--- a/webapps/examples/jsp/jsp2/jspx/svgexample.html
+++ b/webapps/examples/jsp/jsp2/jspx/svgexample.html
@@ -33,7 +33,7 @@
     <p>
     To execute this example, follow these steps:
     <ol>
-      <li>Download <a href="http://xml.apache.org/batik/index.html">Batik</a>,
+      <li>Download <a href="http://xmlgraphics.apache.org/batik/index.html">Apache Batik</a>,
           or any other SVG viewer.</li>
       <li>Copy the following URL:
       <a href="http://localhost:8080/examples/jsp/jsp2/jspx/textRotate.jspx?name=JSPX">
diff --git a/webapps/examples/jsp/jsp2/jspx/textRotate.jspx b/webapps/examples/jsp/jsp2/jspx/textRotate.jspx
index 27a0ca6..1ee71e9 100644
--- a/webapps/examples/jsp/jsp2/jspx/textRotate.jspx
+++ b/webapps/examples/jsp/jsp2/jspx/textRotate.jspx
@@ -16,7 +16,7 @@
 -->
 <!--
   - This example is based off the textRotate.svg example that comes
-  - with Batik.  The original example was written by Bill Haneman.
+  - with Apache Batik.  The original example was written by Bill Haneman.
   - This version by Mark Roth.
   -->
 <svg xmlns="http://www.w3.org/2000/svg"
diff --git a/webapps/examples/websocket/chat.html b/webapps/examples/websocket/chat.html
index 6ab24e9..127eca4 100644
--- a/webapps/examples/websocket/chat.html
+++ b/webapps/examples/websocket/chat.html
@@ -77,7 +77,11 @@
         });
 
         Chat.initialize = function() {
-            Chat.connect('ws://' + window.location.host + '/examples/websocket/chat');
+            if (window.location.protocol == 'http:') {
+                Chat.connect('ws://' + window.location.host + '/examples/websocket/chat');
+            } else {
+                Chat.connect('wss://' + window.location.host + '/examples/websocket/chat');
+            }
         };
 
         Chat.sendMessage = (function() {
diff --git a/webapps/examples/websocket/echo.html b/webapps/examples/websocket/echo.html
index 32d6430..052cea7 100644
--- a/webapps/examples/websocket/echo.html
+++ b/webapps/examples/websocket/echo.html
@@ -104,7 +104,11 @@
         }
 
         function updateTarget(target) {
-            document.getElementById('target').value = 'ws://' + window.location.host + target;
+            if (window.location.protocol == 'http:') {
+                document.getElementById('target').value = 'ws://' + window.location.host + target;
+            } else {
+                document.getElementById('target').value = 'wss://' + window.location.host + target;
+            }
         }
 
         function log(message) {
diff --git a/webapps/examples/websocket/snake.html b/webapps/examples/websocket/snake.html
index 63e3d00..1363f38 100644
--- a/webapps/examples/websocket/snake.html
+++ b/webapps/examples/websocket/snake.html
@@ -109,7 +109,11 @@
                     }
                 }
             }, false);
-            Game.connect('ws://' + window.location.host + '/examples/websocket/snake');
+            if (window.location.protocol == 'http:') {
+                Game.connect('ws://' + window.location.host + '/examples/websocket/snake');
+            } else {
+                Game.connect('wss://' + window.location.host + '/examples/websocket/snake');
+            }
         };
 
         Game.setDirection  = function(direction) {
diff --git a/webapps/manager/WEB-INF/web.xml b/webapps/manager/WEB-INF/web.xml
index 3e13657..8fb7728 100644
--- a/webapps/manager/WEB-INF/web.xml
+++ b/webapps/manager/WEB-INF/web.xml
@@ -44,8 +44,8 @@
       <param-name>debug</param-name>
       <param-value>2</param-value>
     </init-param>
-    <!-- Uncomment this to show proxy sessions from the Backup manager in the
-         sessions list for an application
+    <!-- Uncomment this to show proxy sessions from the Backup manager or a
+         StoreManager in the sessions list for an application
     <init-param>
       <param-name>showProxySessions</param-name>
       <param-value>true</param-value>
diff --git a/webapps/manager/xform.xsl b/webapps/manager/xform.xsl
index a09445b..7082ed3 100644
--- a/webapps/manager/xform.xsl
+++ b/webapps/manager/xform.xsl
@@ -44,6 +44,9 @@
 
   <xsl:template match="jvm">
    <xsl:apply-templates select="memory"/>
+   <b>Memory Pools</b><br />
+   <xsl:apply-templates select="memorypool"/>
+   <hr />
   </xsl:template>
 
   <xsl:template match="memory">
@@ -56,6 +59,18 @@
     </table><hr />
   </xsl:template>
 
+  <xsl:template match="memorypool">
+    <table><tr>
+             <td><b>Name:</b> <xsl:value-of select="@name"/></td>
+             <td><b>Type:</b> <xsl:value-of select="@type"/></td>
+             <td><b>Initial:</b> <xsl:value-of select="@usageInit"/></td>
+             <td><b>Committed:</b> <xsl:value-of select="@usageCommitted"/></td>
+             <td><b>Maximum:</b> <xsl:value-of select="@usageMax"/></td>
+             <td><b>Used:</b> <xsl:value-of select="@usageUsed"/></td>
+           </tr>
+    </table>
+  </xsl:template>
+
   <xsl:template match="connector">
      <b>Connector -- </b> <xsl:value-of select="@name"/><br />
 

-- 
tomcat7: Servlet and JSP engine



More information about the pkg-java-commits mailing list